home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / bbs / tdk_v136.zip / SPAWN.ASM < prev    next >
Assembly Source File  |  1992-03-30  |  89KB  |  3,537 lines

  1. ;
  2. ;    --- Version 3.3 92-03-30 21:39 ---
  3. ;
  4. ;    SPAWN.ASM - Main function for memory swapping spawn call.
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Ferrari electronic GmbH
  9. ;        Beusselstrasse 27
  10. ;        D-1000 Berlin 21
  11. ;        Germany
  12. ;
  13. ;>e
  14. ; Assemble with
  15. ;
  16. ; tasm  /DPASCAL spawn,spawnp          - Turbo Pascal (Tasm only), near
  17. ; tasm  /DPASCAL /DFARCALL spawn,spawnp    - Turbo Pascal (Tasm only), far
  18. ; ?asm  spawn;                  - C, default model (small)
  19. ; ?asm  /DMODL=large spawn          - C, large model
  20. ;
  21. ;    NOTE:    For C, change the 'model' directive below according to your
  22. ;        memory model, or define MODL=xxx on the command line.
  23. ;
  24. ;        For Turbo C Huge model, you must give /DTC_HUGE on the
  25. ;        command line, or define it here.
  26. ;
  27. ;
  28. ; Main function:
  29. ;
  30. ;   PASCAL:
  31. ;       function do_spawn (swapping: integer; 
  32. ;                  execfname: string;
  33. ;               cmdtail: string; 
  34. ;                  envlen: word; 
  35. ;               var envp;
  36. ;               stdin: string; 
  37. ;                   stdout: string;
  38. ;               stderr: string): integer;    
  39. ;
  40. ;   C:
  41. ;       int do_spawn (int swapping,
  42. ;              char *execfname, 
  43. ;              char *cmdtail,
  44. ;              unsigned envlen, 
  45. ;              char *envp,
  46. ;              char *stdin,
  47. ;              char *stdout,
  48. ;              char *stderr)
  49. ;
  50. ;   Parameters:
  51. ;
  52. ;    swapping - swap/spawn/exec function:
  53. ;            < 0: Exec, don't swap
  54. ;                0: Spawn, don't swap
  55. ;            > 0: Spawn, swap
  56. ;                 in this case, prep_swap must have 
  57. ;                 been called beforehand (see below).
  58. ;
  59. ;    cmdtail - command tail for EXEC.
  60. ;
  61. ;    execfname - name and path of file to execute.
  62. ;
  63. ;    envlen - length of environment copy (may be 0).
  64. ;
  65. ;    envp -  pointer to environment block (must be aligned on
  66. ;        paragraph boundary). Unused if envlen is 0.
  67. ;
  68. ;    'cmdtail' and 'execfname' must be zero terminated, even when
  69. ;    calling from Pascal. For Pascal, the length byte of the string
  70. ;    is ignored.
  71. ;
  72. ;   Returns:
  73. ;    0000..00ff:    Returncode of EXECed program
  74. ;    03xx:        DOS-Error xx calling EXEC
  75. ;    0500:        Swapping requested, but prep_swap has not 
  76. ;            been called or returned an error
  77. ;    0501:        MCBs don't match expected setup
  78. ;    0502:        Error while swapping out
  79. ;    06xx:        DOS-Error xx on redirection
  80. ;
  81. ;
  82. ; For swapping, the swap method must be prepared before calling do_spawn.
  83. ;
  84. ;   PASCAL:
  85. ;    function prep_swap (method: word; swapfname: string): integer;
  86. ;   C:
  87. ;    int prep_swap (unsigned method, char *swapfname)
  88. ;
  89. ;   Parameters:
  90. ;
  91. ;    method    - bit-map of allowed swap devices:
  92. ;            01 - Allow EMS
  93. ;            02 - Allow XMS
  94. ;            04 - Allow File swap
  95. ;            10 - Try XMS first, then EMS
  96. ;            40 - Create file as "hidden"
  97. ;            80 - Use "create temp" call for file swap
  98. ;               100 - Don't preallocate file
  99. ;               200 - Check for Network, don't preallocate if net
  100. ;              4000 - Environment block will not be swapped
  101. ;
  102. ;    swapfname - swap file name (may be undefined if the
  103. ;            "method" parameters disallows file swap).
  104. ;            The string must be zero terminated, even
  105. ;            when calling from Pascal. For Pascal, the 
  106. ;            length byte of the string is ignored.
  107. ;
  108. ;   Returns:
  109. ;
  110. ;       A positive integer on success:
  111. ;        1 - EMS swap initialized
  112. ;        2 - XMS swap initialized
  113. ;        4 - File swap initialized
  114. ;    A negative integer on failure:
  115. ;        -1 - Couldn't allocate swap space
  116. ;        -2 - The spawn module is located too low in memory
  117. ;<
  118. ;>d
  119. ; Assemblierung mit
  120. ;
  121. ; tasm  /DPASCAL spawn,spawnp          - Turbo Pascal (nur Tasm), near
  122. ; tasm  /DPASCAL /DFARCALL spawn,spawnp    - Turbo Pascal (nur Tasm), far
  123. ; ?asm  spawn;                  - C, default model (small)
  124. ; ?asm  /DMODL=large spawn          - C, large model
  125. ;
  126. ;    HINWEIS: Für C können Sie entweder die folgende 'model'-Direktive
  127. ;        Ihrem Speichermodell entsprechend ändern, oder beim
  128. ;        Assemblieren MODL=xxx in der Kommandozeile definieren.
  129. ;
  130. ;        Für Turbo C Huge model müssen Sie /DTC_HUGE beim Assemblieren
  131. ;        angeben, oder das Symbol in dieser Quelle definieren.
  132. ;
  133. ;
  134. ; Haupfunktion:
  135. ;
  136. ;   PASCAL:
  137. ;       function do_spawn (swapping: integer; 
  138. ;                  execfname: string;
  139. ;               cmdtail: string; 
  140. ;                  envlen: word; 
  141. ;               var envp)
  142. ;
  143. ;   C:
  144. ;       int do_spawn (int swapping,
  145. ;              char *execfname, 
  146. ;              char *cmdtail,
  147. ;              unsigned envlen, 
  148. ;              char *envp)
  149. ;
  150. ;   Parameter:
  151. ;
  152. ;    swapping - swap/spawn/exec Funktion:
  153. ;            < 0: Exec, kein Auslagern, keine Rückkehr
  154. ;                0: Spawn, kein Auslagern
  155. ;            > 0: Spawn, Auslagern
  156. ;                 in diesem Fall muß vor Aufruf die Funktion
  157. ;                 prep_swap aufgerufen worden sein (siehe unten).
  158. ;
  159. ;    cmdtail - Parameter für das aufgerufene Programm.
  160. ;
  161. ;    execfname - Name und Pfad des auszuführenden Programms.
  162. ;
  163. ;    envlen - Länge der Umgebungsvariablen-Kopie (kann 0 sein).
  164. ;
  165. ;    envp -  Zeiger auf Umgebungsvariablen-Block (muß auf Paragraph-
  166. ;        Grenze adjustiert sein). Wird nicht benutzt wenn der
  167. ;        envlen Parameter 0 ist.
  168. ;
  169. ;    'cmdtail' und 'execfname' müssen 0-Terminiert sein, selbst wenn
  170. ;    der Aufruf von Pascal erfolgt. Bei Aufruf von Pascal wird das
  171. ;    Längenbyte am Anfang des Strings ignoriert.
  172. ;
  173. ;   Liefert:
  174. ;
  175. ;    0000..00ff:    Returncode des ausgeführten Programms
  176. ;    03xx:        DOS-Fehler xx beim Aufruf von EXEC
  177. ;    0500:        Auslagern angefordert, aber prep_swap wurde
  178. ;            nicht aufgerufen oder nicht erfolgreich ausgeführt
  179. ;    0501:        MCBs sind fehlerhaft bzw. verändert
  180. ;    0502:        Fehler bei Auslagerung
  181. ;    06xx:        DOS-Fehler xx bei Redirection
  182. ;
  183. ;
  184. ; Um Auslagern zu können, muß die Auslagerungs-Methode vor Aufruf von
  185. ; do_spawn vorbereitet werden.
  186. ;
  187. ;   PASCAL:
  188. ;    function prep_swap (method: byte; swapfname: string): integer;
  189. ;   C:
  190. ;    int prep_swap (unsigned char method, char *swapfname)
  191. ;
  192. ;   Parameter:
  193. ;
  194. ;    method    - Bit-Map der zulässigen Auslagerungsziele und Optionen:
  195. ;            01 - EMS zulassen
  196. ;            02 - XMS zulassen
  197. ;            04 - Datei zulassen
  198. ;            10 - Erst XMS, dann EMS versuchen
  199. ;            40 - Datei "hidden" erzeugen
  200. ;            80 - "create temp" Funktion bei Datei-Auslagerung
  201. ;               100 - Datei nicht präallozieren
  202. ;               200 - Netzwerk prüfen, nicht präallozieren wenn Netz
  203. ;              4000 - Environmentblock nicht auslagern
  204. ;
  205. ;    swapfname - Auslagerungsdateiname bzw. Pfad (kann undefiniert
  206. ;            sein wenn der "Method" Parameter keine Dateiauslagerung
  207. ;            zulässt).
  208. ;            Der String muß 0-Terminiert sein, selbst wenn
  209. ;            der Aufruf von Pascal erfolgt. Bei Aufruf von Pascal 
  210. ;            wird das Längenbyte am Anfang des Strings ignoriert.
  211. ;
  212. ;   Liefert:
  213. ;
  214. ;       Einen positiven Wert bei Erfolg:
  215. ;        1 - EMS Auslagerung initialisiert
  216. ;        2 - XMS Auslagerung initialisiert
  217. ;        4 - Datei-Auslagerung initialisiert
  218. ;    Einen negativen Wert bei Fehler:
  219. ;        -1 - Kein Platz für Auslagerung
  220. ;        -2 - Das "spawn"-Modul ist zu nah am Beginn des Programms
  221. ;<
  222. ;--------------------------------------------------------------------------
  223. ;
  224. ;>e
  225. ;    Set NO_INHERIT to FALSE if you don't want do_exec to mess with
  226. ;    the handle table in the PSP, and/or you do want the child process
  227. ;    to inherit all open files.
  228. ;    If NO_INHERIT is TRUE, only the first five handles (the standard
  229. ;    ones) will be inherited, all others will be hidden. This allows
  230. ;    the child to open more files, and also protects you from the child
  231. ;    messing with any open handles.
  232. ;    NO_INHERIT should always be TRUE if you use functions to extend
  233. ;    the handle table (for more than 20 open files).
  234. ;
  235. ;    Set REDIRECT to FALSE if you do not want do_spawn to support redirection.
  236. ;
  237. ;    The following defines are for Turbo Pascal only:
  238. ;        Set PAS_FREE to TRUE to not swap the unused heap space.
  239. ;        Set TPAS_6 to TRUE for Turbo Pascal version 6.
  240. ;
  241. ;    When PAS_FREE is TRUE, the unused heap, i.e. the space between
  242. ;    HeapPtr and FreePtr for TP 5.x, or the space between HeapPtr and
  243. ;    HeapEnd for TP6.x, is temporarily chained into the DOS free space 
  244. ;    list, and is not swapped out. Depending on your applications heap 
  245. ;    usage, this can save a large amount of swap space, and considerably
  246. ;    speed up the swap.
  247. ;<
  248. ;>d
  249. ;    Setzen Sie NO_INHERIT auf FALSE wenn Sie nicht wollen, daß do_spawn
  250. ;    die Handle-Tabelle im PSP modifiziert, und/oder der Kindprozess
  251. ;    alle offenen Dateien erben soll.
  252. ;    Wenn NO_INHERIT TRUE ist, werden nur die ersten fünf Handles
  253. ;    (die Standard-Handles) vererbt, alle anderen werden versteckt.
  254. ;    Dies erlaubt dem Kindprozess, mehr Dateien zu öffnen, und schützt
  255. ;    Sie außerdem vor Änderungen an offenen Dateien.
  256. ;    NO_INHERIT sollte stets TRUE sein, wenn Sie Funktionen zur
  257. ;    Erweiterung der Handle-Tabelle (für mehr als 20 offene Dateien)
  258. ;    benutzen.
  259. ;
  260. ;    Setzen Sie REDIRECT auf FALSE wenn do_spawn keine Dateiumleitung 
  261. ;    unterstützen soll.
  262. ;
  263. ;    Die folgenden Definitionen werden nur für Turbo Pascal benötigt:
  264. ;        Setzen Sie PAS_FREE auf TRUE wenn der unbenutzte Heap
  265. ;        nicht ausgelagert werden soll.
  266. ;        Setzen Sie TPAS_6 auf TRUE für Turbo Pascal Version 6.
  267. ;
  268. ;    Wenn PAS_FREE TRUE ist, wird der nicht belegte Heap, d.h. der
  269. ;    Bereich zwischen HeapPtr und FreePtr für TP 5.x, bzw. zwischen
  270. ;    HeapPtr und HeapEnd für TP 6.x, temporär in die DOS-Freispeicher-
  271. ;    Liste eingefügt, und damit nicht ausgelagert. Abhängig von der
  272. ;    Heap-Belegung Ihrer Applikation kann dies den Speicherbedarf
  273. ;    für die Auslagerung wesentlich verringern, und die Auslagerung
  274. ;    beschleunigen.
  275. ;<
  276. ;
  277. FALSE        =    0
  278. TRUE        =    NOT FALSE
  279. ;
  280. NO_INHERIT    =    TRUE
  281. REDIRECT    =    TRUE
  282. ;
  283. PAS_FREE    =    FALSE
  284. TPAS_6        =    FALSE
  285. ;
  286. ;
  287.     IFDEF    PASCAL
  288.     .model    tpascal
  289.     IFDEF    FARCALL
  290.     %out    Pascal, far calls
  291.     ELSE
  292.     %out    Pascal, near calls
  293.     ENDIF
  294. ;
  295.     extrn    prefixseg: word
  296.     IF    PAS_FREE
  297.     extrn    HeapPtr: dword
  298.     IF    TPAS_6
  299.     extrn    HeapEnd: dword
  300.     ELSE
  301.     extrn    FreePtr: dword
  302.     ENDIF
  303.     ENDIF
  304. ;
  305. ptrsize    =    1
  306.     ELSE
  307.     IFNDEF    MODL
  308.     .model    small,c
  309.     %out    small model
  310.     ELSE
  311. %    .model    MODL,c
  312. %    %out    MODL model
  313.     ENDIF
  314. ;
  315. ptrsize    =    @DataSize
  316. ;
  317.     extrn    _psp: word
  318.     ENDIF
  319. ;
  320.     public    do_spawn
  321.     public    prep_swap
  322.     IFNDEF    PASCAL
  323.     public    swap_prep
  324.     ENDIF
  325. ;
  326. stacklen    =    256        ;e local stack
  327.                     ;d Lokaler Stack
  328. ;
  329. ;e    "ems_size" is the EMS block size: 16k.
  330. ;d    "ems_size" ist die EMS-Blockgröße: 16k.
  331. ;
  332. ems_size    =    16 * 1024    ;e EMS block size
  333.                     ;d EMS-Seiten-Größe
  334. ems_parasize    =    ems_size / 16    ;e same in paragraphs
  335.                     ;d desgleichen in Paragraphen
  336. ems_shift    =    10        ;e shift factor for paragraphs
  337.                     ;d Schiebefaktor für Paragraphen
  338. ems_paramask    =    ems_parasize-1    ;e block mask
  339.                     ;d Maske für Paragraphen
  340. ;
  341. ;e    "xms_size" is the unit of measurement for XMS: 1k
  342. ;d    "xms_size" ist die Blockgröße für XMS: 1k
  343. ;
  344. xms_size    =    1024        ;e XMS block size
  345.                     ;d XMS-Block-Größe
  346. xms_parasize    =    xms_size / 16    ;e same in paragraphs
  347.                     ;d desgleichen in Paragraphen
  348. xms_shift    =    6        ;e shift factor for paragraphs
  349.                     ;d Schiebefaktor für Paragraphen
  350. xms_paramask    =    xms_parasize-1    ;e block mask
  351.                     ;d Maske für Paragraphen
  352. ;
  353. ;e    Method flags
  354. ;d    Auslagerungsmethoden-Flags
  355. ;
  356. USE_EMS        =    01h
  357. USE_XMS        =    02h
  358. USE_FILE    =    04h
  359. XMS_FIRST    =    10h
  360. HIDE_FILE    =    40h
  361. CREAT_TEMP    =    80h
  362. NO_PREALLOC    =    100h
  363. CHECK_NET    =    200h
  364. DONT_SWAP_ENV    =    4000h
  365. ;
  366. ;e    Return codes
  367. ;d    Resultatcodes
  368. ;
  369. RC_TOOLOW    =    0102h
  370. RC_BADPREP    =    0500h
  371. RC_MCBERROR    =    0501h
  372. RC_SWAPERROR    =    0502h
  373. RC_REDIRFAIL    =    0600h
  374. ;
  375. EMM_INT        =    67h
  376. ;
  377. ;e    The EXEC function parameter block
  378. ;d    Der Parameterblock für die EXEC-Funktion
  379. ;
  380. exec_block    struc
  381. envseg    dw    ?        ;e environment segment
  382.                 ;d Segmentadresse Umgebungsvariablenblock
  383. ppar    dw    ?        ;e program parameter string offset
  384.                 ;d Programmparameterstring Offset
  385. pparseg    dw    ?        ;e program parameter string segment
  386.                 ;d Programmparameterstring Segment
  387. fcb1    dw    ?        ; FCB offset
  388. fcb1seg    dw    ?        ; FCB segment
  389. fcb2    dw    ?        ; FCB offset
  390. fcb2seg    dw    ?        ; FCB segment
  391. exec_block    ends
  392. ;
  393. ;e    Structure of an XMS move control block
  394. ;d    Struktur eines XMS move Kontrollblocks
  395. ;
  396. xms_control    struc
  397. lenlo        dw    ?    ;e length to move (doubleword)
  398.                 ;d Länge für Move (Doppelwort)
  399. lenhi        dw    ?
  400. srchnd        dw    ?    ;e source handle (0 for standard memory)
  401.                 ;d Quell-Handle (0 für Standardspeicher)
  402. srclo        dw    ?    ;e source address (doubleword or seg:off)
  403.                 ;d Quell-Adresse (Doppelwort oder seg:off)
  404. srchi        dw    ?
  405. desthnd        dw    ?    ;e destination handle (0 for standard memory)
  406.                 ;d Ziel-Handle (0 für Standardspeicher)
  407. destlo        dw    ?    ;e destination address (doubleword or seg:off)
  408.                 ;d Ziel-Adresse (Doppelwort oder seg:off)
  409. desthi        dw    ?
  410. xms_control    ends
  411. ;
  412. ;e    The structure of the start of an MCB (memory control block)
  413. ;d    Die Struktur des Beginns eines MCB (Speicher-Kontrollblock)
  414. ;
  415. mcb        struc
  416. id        db    ?
  417. owner        dw    ?
  418. paras        dw    ?
  419. mcb        ends
  420. ;>e
  421. ;    The structure of an internal MCB descriptor.
  422. ;    CAUTION: This structure is assumed to be no larger than 16 bytes
  423. ;    in several places in the code, and to be exactly 16 bytes when
  424. ;    swapping in from file. Be careful when changing this structure.
  425. ;<
  426. ;>d
  427. ;    Die Struktur eines internen MCB-Descriptors.
  428. ;    ACHTUNG: An mehreren Stellen im Code wird angenommen, daß die
  429. ;    Länge dieser Struktur 16 Bytes nicht überschreitet. Beim
  430. ;    Zurücklesen von Datei wird angenommen, daß die Länge exakt 16
  431. ;    Bytes beträgt. Bei Änderungen in dieser Struktur ist daher
  432. ;    Vorsicht geboten.
  433. ;<
  434. mcbdesc        struc
  435. addr        dw    ?    ;e paragraph address of the MCB
  436.                 ;d Paragraph-Adresse des MCB
  437. msize        dw    ?    ;e size in paragraphs (excluding header)
  438.                 ;d Größe in Paragraphen (Ausschließlich Header)
  439. swoffset    dw    ?    ;e swap offset (0 in all blocks except first)
  440.                 ;d Auslagerungs-Offset (0 in allen Blöcken 
  441.                 ;d außer dem ersten)
  442. swsize        dw    ?    ;e swap size (= msize + 1 except in first)
  443.                 ;d Auslagerungsgröße (= msize + 1 außer
  444.                 ;d im ersten Block)
  445. num_follow    dw    ?    ;e number of following MCBs
  446.                 ;d Zahl der folgenden MCBs
  447.         dw    3 dup(?) ;e pad to paragraph (16 bytes)
  448.                  ;d Auffüllen auf Paragraphen (16 Bytes)
  449. mcbdesc        ends
  450. ;
  451. ;e    The variable block set up by prep_swap
  452. ;d    Der Variablenblock der durch prep_swap initialisiert wird
  453. ;
  454. prep_block    struc
  455. xmm        dd    ?        ;e XMM entry address
  456.                     ;d Einsprungadresse XMM
  457. first_mcb    dw    ?        ;e Segment of first MCB
  458.                     ;d Segment des ersten MCB
  459. psp_mcb        dw    ?        ;e Segment of MCB of our PSP
  460.                     ;d Segment des MCB unseres PSP
  461. env_mcb        dw    ?        ;e MCB of Environment segment
  462.                     ;d MCB des Umgebungsvariablenblocks
  463. noswap_mcb    dw    ?        ;e Env MCB that may not be swapped
  464.                     ;d Env MCB der nicht Ausgelagert wird
  465.         IF    NOT NO_INHERIT
  466. noswap_mcb2    dw    ?        ;e Handle MCB that may not be swapped
  467.                     ;d Handle MCB der nicht Ausgelagert wird
  468.         ENDIF
  469.         IFDEF    PASCAL
  470.         IF    PAS_FREE
  471. pmemid        db    ?
  472. pmempar        dw    ?
  473.         ENDIF
  474.         ENDIF
  475. ems_pageframe    dw    ?        ;e EMS page frame address
  476.                     ;d EMS-Seiten-Adresse
  477. handle        dw    ?        ;e EMS/XMS/File handle
  478.                     ;d Handle für EMS/XMS/Datei
  479. total_mcbs    dw    ?        ;e Total number of MCBs
  480.                     ;d Gesamtzahl MCBs
  481. swapmethod    db    ?        ;e Method for swapping
  482.                     ;d Auslagerungsmethode
  483. swapfilename    db    81 dup(?)    ;e Swap file name if swapping to file
  484.                     ;d Auslagerungsdateiname
  485. prep_block    ends
  486. ;
  487. ;----------------------------------------------------------------------
  488. ;>e
  489. ;    Since we'll be moving code and data around in memory,
  490. ;    we can't address locations in the resident block with
  491. ;    normal address expressions. MASM does not support
  492. ;    defining variables with a fixed offset, so we have to resort
  493. ;    to a kludge, and define the shrunk-down code as a structure.
  494. ;    It would also be possible to use an absolute segment for the
  495. ;    definition, but this is not supported by the Turbo Pascal linker.
  496. ;
  497. ;    All references to low-core variables from low-core itself 
  498. ;    are made through DS, so we define a text macro "lmem" that 
  499. ;    expands to "ds:". When setting up low core from the normal
  500. ;    code, ES is used to address low memory, so this can't be used.
  501. ;<
  502. ;>d
  503. ;    Da Code und Daten in andere Speicherbereiche kopiert werden,
  504. ;    können Adressen im residenten Teil nicht mit normalen Adress-
  505. ;    ausdrücken angesprochen werden. MASM unterstützt leider nicht
  506. ;    die Definition von Variablen mit festen Offsets, sodaß wir
  507. ;    den residenten Teil als Struktur definieren müssen. Eine Definition
  508. ;    als absolutes Segment wäre zwar in MASM möglich, dies wird jedoch
  509. ;    vom Turbo Pascal Linker nicht unterstützt.
  510. ;
  511. ;    Alle Referenzen auf Variablen im residenten Teil von diesem
  512. ;    Teil selbst geschehen über DS, hierfür kann daher ein Text-Makro
  513. ;    "lmem" definiert werden, das zu "ds:" expandiert wird. Beim
  514. ;    Aufsetzen des residenten Teils vom normalen Programm geschieht
  515. ;    die Adressierung über ES, sodaß dieses Makro dort nicht verwendet
  516. ;    werden darf.
  517. ;<
  518. lmem    equ    <ds:>
  519. ;>e
  520. ;    The memory structure for the shrunk-down code, excluding the
  521. ;    code itself. The code follows this block.
  522. ;    The start of this block is the PSP.
  523. ;<
  524. ;>d
  525. ;    Die Struktur des residenten Teils, ausschließlich des Programm-
  526. ;    Codes. Der Programmcode folgt diesem Block.
  527. ;    Der Beginn dieses Blocks ist der PSP.
  528. ;<
  529. parseg        struc
  530.         db    18h dup(?)
  531. psp_handletab    db    20 dup(?)    ; Handle Table
  532. psp_envptr    dw    ?        ; Environment Pointer
  533.         dd    ?
  534. psp_handlenum    dw    ?        ; Number of Handles (DOS >= 3.3)
  535. psp_handleptro    dw    ?        ; Handle Table Pointer (DOS >= 3.3)
  536. psp_handleptrs    dw    ?        ; Handle Table Pointer Segment
  537.         db    5ch-38h dup(?)    ;e start after PSP
  538.                     ;d Start nach PSP
  539. ;
  540. save_ss        dw    ?        ;e 5C - saved global ss
  541.                     ;d 5C - Sicherung globales SS
  542. save_sp        dw    ?        ;e 5E - saved global sp
  543.                     ;d 5E - Sicherung globaler SP
  544. xfcb1        db    16 dup(?)    ;e 60..6F - default FCB
  545.                     ;d 60..6F - Standard-FCB
  546. xfcb2        db    16 dup(?)    ;e 70..7F - default FCB
  547.                     ;d 70..7f - Standard-FCB
  548. zero        dw    ?        ;e 80 Zero command tail length (dummy)
  549.                     ;d 80 Null-Kommandozeile (Dummy)
  550. ;
  551. expar        db    TYPE exec_block dup (?) ; exec-parameter-block
  552. spx        dw    ?        ;e saved local sp
  553.                     ;d Sicherung lokaler SP
  554. div0_off    dw    ?        ;e divide by zero vector save
  555.                     ;d Sicherung divide-by-zero Vektor
  556. div0_seg    dw    ?
  557.         IF    NO_INHERIT
  558. lhandlesave    db    26 dup(?)    ;e saved handle table and pointer
  559.                     ;d Sicherung Handle-Tabelle und Pointer
  560.         IF    REDIRECT
  561. lredirsav    db    6 dup(?)    ;e saved redirection handles
  562.                     ;d Sicherung Umleitungs-Handles
  563.         ENDIF
  564.         ENDIF
  565.         IF    REDIRECT
  566. lstdinsav    dw    3 dup(?)    ;e duped redirection handles
  567.                     ;d Umleitungs-Handles aus 'dup'
  568.         ENDIF
  569. filename    db    82 dup(?)    ;e exec filename
  570.                     ;d EXEC-Dateiname
  571. progpars    db    128 dup(?)    ;e command tail
  572.                     ;d Kommandozeile
  573.         db    stacklen dup(?)    ;e local stack space
  574.                     ;d Lokaler Stackbereich
  575. mystack        db    ?
  576. lprep        db    TYPE prep_block dup(?)    ;e the swapping variables
  577.                         ;d die Auslagerungsvariablen
  578. lcurrdesc    db    TYPE mcbdesc dup(?)    ;e the current MCB descriptor
  579.                         ;d Descriptor aktueller MCB
  580. lxmsctl        db    TYPE xms_control dup(?)
  581. eretcode    dw    ?        ;e EXEC return code
  582.                     ;d Resultatcode EXEC
  583. retflags    dw    ?        ;e EXEC return flags
  584.                     ;d Resultatflags EXEC
  585. cgetmcb        dw    ?        ;e address of get_mcb
  586.                     ;d Adresse von get_mcb
  587. ;
  588. parseg    ends
  589. ;
  590. param_len    =    ((TYPE parseg + 1) / 2) * 2    ; make even
  591. codebeg        =    param_len
  592. ;
  593.     .code
  594. ;
  595. ;------------------------------------------------------------------------
  596. ;
  597. lowcode_begin:
  598. ;>e
  599. ;       The following parts of the program code will be moved to
  600. ;    low core and executed there, so there must be no absolute 
  601. ;    memory references.
  602. ;    The call to get_mcb must be made indirect, since the offset
  603. ;    from the swap-in routine to get_mcb will not be the same
  604. ;    after moving.
  605. ;
  606. ;
  607. ;    get_mcb allocates a block of memory by modifying the MCB chain
  608. ;    directly.
  609. ;
  610. ;    On entry, lcurrdesc has the mcb descriptor for the block to
  611. ;          allocate.
  612. ;
  613. ;    On exit,  Carry is set if the block couldn't be allocated.
  614. ;
  615. ;    Uses     AX, BX, CX, ES
  616. ;    Modifies lprep.first_mcb
  617. ;<
  618. ;>d
  619. ;       Der folgende Teil des Programm-Codes wird in den unteren Speicher-
  620. ;    bereich kopiert und dort ausgeführt, es dürfen daher keine
  621. ;    absoluten Speicheradressen verwendet werden.
  622. ;    Der Aufruf von get_mcb muß indirekt erfolgen, da der Offset
  623. ;    der Einlagerungs-Routine zu get_mcb nach dem Kopieren nicht
  624. ;    mehr mit der Definition übereinstimmt.
  625. ;
  626. ;
  627. ;    get_mcb alloziert einen Speicherblock durch direkte Modifikation
  628. ;        der MCB-Kette.
  629. ;
  630. ;    Bei Einsprung enthält lcurrdesc den Deskriptor für den zu
  631. ;        allozierenden Block.
  632. ;
  633. ;    Bei Rückkehr ist das Carry-Flag gesetzt wenn der Block nicht
  634. ;        alloziert werden konnte.
  635. ;
  636. ;    Benutzt    AX, BX, CX, ES
  637. ;    Modifiziert lprep.first_mcb
  638. ;<
  639. get_mcb    proc    near
  640. ;
  641.     mov    ax,lmem lprep.first_mcb
  642.     mov    bx,lmem lcurrdesc.addr
  643. ;
  644. getmcb_loop:
  645.     mov    es,ax
  646.     cmp    ax,bx
  647.     ja    gmcb_abort        ;e halt if MCB > wanted
  648.                     ;d Abbrechen wenn MCB > gewünschtem
  649.     je    mcb_found        ;e jump if same addr as wanted
  650.                     ;d jump wenn Adresse gleich gewünschter
  651.     add    ax,es:paras        ;e last addr
  652.                     ;d Letze Adresse
  653.     inc    ax            ; next mcb
  654.     cmp    ax,bx
  655.     jbe    getmcb_loop        ;e Loop if next <= wanted
  656.                     ;d Nochmal wenn nächster <= gewünschter
  657. ;
  658. ;>e
  659. ;    The wanted MCB starts within the current MCB. We now have to
  660. ;    create a new MCB at the wanted position, which is initially
  661. ;    free, and shorten the current MCB to reflect the reduced size.
  662. ;<
  663. ;>d
  664. ;    Der gewünschte MCB beginnt innerhalb des laufenden MCB. Es muß
  665. ;    nun ein MCB an der gewünschten Position eingerichtet werden, und
  666. ;    der laufende MCB ist zu kürzen.
  667. ;<
  668.     cmp    es:owner,0
  669.     jne    gmcb_abort        ;e halt if not free
  670.                     ;d Abbruch wenn nicht frei
  671.     mov    bx,es            ;e current
  672.                     ;d laufender
  673.     inc    bx            ;e + 1 (header doesn't count)
  674.                     ;d + 1 (Header zählt nicht)
  675.     mov    ax,lmem lcurrdesc.addr
  676.     sub    ax,bx            ;e paragraphs between MCB and wanted
  677.                     ;d Paragraphen zwischen MCB 
  678.                     ;d und gewünschtem
  679.     mov    bx,es:paras        ;e paras in current MCB
  680.                     ;d Paragraphen in laufendem MCB
  681.     sub    bx,ax            ;e remaining paras
  682.                     ;d Restliche Paragraphen
  683.     dec    bx            ;e -1 for header
  684.                     ;d -1 für Header
  685.     mov    es:paras,ax        ;e set new size for current
  686.                     ;d neue Größe für laufenden Setzen
  687.     mov    cl,es:id        ;e old id
  688.                     ;d Alte ID
  689.     mov    es:id,4dh        ;e set id: there is a next
  690.                     ;d Setze ID: es gibt einen nächsten
  691.     mov    ax,lmem lcurrdesc.addr
  692.     mov    es,ax
  693.     mov    es:id,cl        ;e and init to free
  694.                     ;d und initialisiere auf Frei
  695.     mov    es:owner,0
  696.     mov    es:paras,bx
  697. ;>e
  698. ;    We have found an MCB at the right address. If it's not free,
  699. ;    abort. Else check the size. If the size is ok, we're done 
  700. ;    (more or less).
  701. ;<
  702. ;>d
  703. ;    Wir haben einen MCB an der korrekten Adresse. Falls er nicht
  704. ;    frei ist, abbrechen. Sonst Größe prüfen. Falls die Größe
  705. ;    korrekt ist, sind wir (mehr oder weniger) fertig.
  706. ;<
  707. mcb_found:
  708.     mov    es,ax
  709.     cmp    es:owner,0
  710.     je    mcb_check        ;e continue if free
  711.                     ;d weiter wenn Frei
  712. ;
  713. gmcb_abort:
  714.     stc
  715.     ret
  716. ;
  717. mcb_check:
  718.     mov    ax,es:paras        ;e size
  719.                     ;d Größe
  720.     cmp    ax,lmem lcurrdesc.msize    ;e needed size
  721.                     ;d gewünschte Größe
  722.     jae    mcb_ok            ;e ok if enough space
  723.                     ;d OK wenn genug Platz
  724. ;>e
  725. ;    If there's not enough room in this MCB, check if the next
  726. ;    MCB is free, too. If so, coalesce both MCB's and check again.
  727. ;<
  728. ;>d
  729. ;    Wenn in diesem MCB nicht genug Platz ist, den nächsten MCB
  730. ;    prüfen ob er ebenfalls frei ist. Falls ja, beide Blöcke
  731. ;    kombinieren und nochmals prüfen.
  732. ;<
  733.     cmp    es:id,4dh
  734.     jnz    gmcb_abort        ;e halt if no next
  735.                     ;d Abbruch wenn kein nächster
  736.     push    es            ;e save current
  737.                     ;d Laufenden sichern
  738.     mov    bx,es
  739.     add    ax,bx
  740.     inc    ax            ;e next MCB
  741.                     ;d nächter MCB
  742.     mov    es,ax
  743.     cmp    es:owner,0        ;e next free ?
  744.                     ;d ist der nächste frei?
  745.     jne    gmcb_abort        ;e halt if not
  746.                     ;d Abbruch wenn nein
  747.     mov    ax,es:paras        ;e else load size
  748.                     ;d sonst Größe laden
  749.     inc    ax            ;e + 1 for header
  750.                     ;d + 1 für Header
  751.     mov    cl,es:id        ;e and load ID
  752.                     ;d und ID laden
  753.     pop    es            ;e back to last MCB
  754.                     ;d zurück zum letzten MCB
  755.     add    es:paras,ax        ;e increase size
  756.                     ;d Größe erhöhen
  757.     mov    es:id,cl        ;e and store ID
  758.                     ;d und ID abspeichern
  759.     jmp    mcb_check        ;e now try again
  760.                     ;d nochmal versuchen
  761. ;>e
  762. ;    The MCB is free and large enough. If it's larger than the
  763. ;    wanted size, create another MCB after the wanted.
  764. ;<
  765. ;>d
  766. ;    Der MCB ist frei und groß genug. Wenn er größer als die gewünschte
  767. ;    Größe ist, muß ein weiterer MCB nach dem gewünschten erzeugt werden.
  768. ;<
  769. mcb_ok:
  770.     mov    bx,es:paras
  771.     sub    bx,lmem lcurrdesc.msize
  772.     jz    mcb_no_next        ;e ok, no next to create
  773.                     ;d OK, kein neuer einzurichten
  774.     push    es
  775.     dec    bx            ;e size of next block
  776.                     ;d Größe des nächsten Blocks
  777.     mov    ax,es
  778.     add    ax,lmem lcurrdesc.msize
  779.     inc    ax            ;e next MCB addr
  780.                     ;d Adresse des nächsten MCB
  781.     mov    cl,es:id        ;e id of this block
  782.                     ;d ID dieses Blocks
  783.     mov    es,ax            ;e address next
  784.                     ;d nächsten adressieren
  785.     mov    es:id,cl        ;e store id
  786.                     ;d ID abspeichern
  787.     mov    es:paras,bx        ;e store size
  788.                     ;d Größe abspeichern
  789.     mov    es:owner,0        ;e and mark as free
  790.                     ;d und als frei markieren
  791.     pop    es            ;e back to old MCB
  792.                     ;d zurück zum alten MCB
  793.     mov    es:id,4dh        ;e mark next block present
  794.                     ;d markieren daß weiterer existiert
  795.     mov    ax,lmem lcurrdesc.msize    ;e and set size to wanted
  796.                     ;d und Größe auf gewünschte setzen
  797.     mov    es:paras,ax
  798. ;
  799. mcb_no_next:
  800.     mov    es:owner,cx        ;e set owner to current PSP
  801.                     ;d owner auf laufenden PSP setzen
  802. ;>e
  803. ;    Set the 'first_mcb' pointer to the current one, so we don't
  804. ;    walk through all the previous blocks the next time.
  805. ;    Also, check if the block we just allocated is the environment
  806. ;    segment of the program. If so, restore the environment pointer
  807. ;    in the PSP.
  808. ;<
  809. ;>d
  810. ;    Der 'first_mcb'-Pointer wird auf den aktuellen gesetzt,
  811. ;    damit beim nächsten Mal nicht wieder alle vorangegangenen
  812. ;    Blöcke abgelatscht werden müssen.
  813. ;    Außerdem wird der gerade allozierte Block geprüft, ob es der
  814. ;    Umgebungsvariablenblock des Programms ist. Wenn ja, wird der
  815. ;    entsprechende Pointer im PSP wiederhergestellt.
  816. ;<
  817.     mov    ax,es
  818.     mov    lmem lprep.first_mcb,ax
  819.     cmp    lmem lprep.env_mcb,ax
  820.     jne    getmcb_finis
  821.     inc    ax
  822.     mov    lmem psp_envptr,ax
  823. ;
  824. getmcb_finis:
  825.     clc
  826.     ret                ;e all finished (whew!)
  827.                     ;d endlich geschafft
  828. ;
  829. get_mcb    endp
  830. ;
  831. ;
  832. ireti:
  833.     iret
  834. ;
  835. ;>e
  836. ;    The actual EXEC call.
  837. ;    Registers on entry:
  838. ;        BX    = paragraphs to keep (0 if no swap)
  839. ;        CX     = length of environment to copy (words) or zero
  840. ;        DS:SI    = environment source
  841. ;        ES:DI    = environment destination
  842. ;        (ES = our low core code segment)
  843. ;
  844. ;
  845. ;    copy environment buffer down if present
  846. ;<
  847. ;>d
  848. ;    Der eigentliche EXEC Aufruf.
  849. ;    Register bei Einsprung:
  850. ;        BX    = Residente Paragraphen (0 wenn keine Auslagerung)
  851. ;        CX     = Länge des Umgebungsvariablenblocks in Worten oder 0
  852. ;        DS:SI    = Quelladresse Umgebungsvariablenblock
  853. ;        ES:DI    = Zieladresse Umgebungsvariablenblock
  854. ;        (ES = Adresse residenter Teil)
  855. ;
  856. ;
  857. ;    Umgebungsvariablenblock nach unten kopieren wenn vorhanden
  858. ;<
  859. doexec:
  860.     jcxz    noenvcpy
  861.     rep movsw
  862. ;
  863. noenvcpy:
  864.     push    es            ; DS = ES = low core = PSP
  865.     pop    ds
  866.     or    bx,bx
  867.     jz    no_shrink
  868. ;
  869. ;e    first, shrink the base memory block down.
  870. ;d    Zuerst den Basisblock reduzieren.
  871. ;
  872.         mov    ah,04ah
  873.     int     21h                     ; resize memory block
  874. ;>e
  875. ;    Again walk all MCBs. This time, all blocks owned by the 
  876. ;    current process are released.
  877. ;<
  878. ;>d
  879. ;    Wieder mal alle MCBs durchgehen. Diesmal werden alle Blöcke 
  880. ;    die zu diesem Prozeß gehören freigegeben.
  881. ;<
  882.     mov    si,lmem lprep.first_mcb
  883.     or    si,si
  884.     jz    no_shrink
  885.     mov    dx,lmem lprep.psp_mcb
  886.     mov    bx,dx
  887.     inc    bx            ; base PSP (MCB owner)
  888.     mov    di,lmem lprep.noswap_mcb
  889. ;
  890. free_loop:
  891.     cmp    si,dx
  892.     je    free_next        ;e don't free base block
  893.                     ;d Basisblock nicht freigeben
  894.     cmp    si,di
  895.     je    free_next
  896.  
  897.     IF    NOT NO_INHERIT
  898.     cmp    si,lmem lprep.noswap_mcb2
  899.     je    free_next
  900.     ENDIF
  901.  
  902.     mov    es,si
  903.     cmp    bx,es:owner        ;e our process?
  904.                     ;d unser Prozeß?
  905.     jne    free_next        ;e next if not
  906.                     ;d nächsten wenn nein
  907.     cmp    si,lmem lprep.env_mcb    ;e is this the environment block?
  908.                     ;d ist dies der Umgebungsvariablenblock?
  909.     jne    free_noenv
  910.     mov    ds:psp_envptr,0        ;e else clear PSP pointer
  911.                     ;d sonst PSP-pointer löschen
  912. ;
  913. free_noenv:
  914.     inc    si
  915.     mov    es,si
  916.     dec    si
  917.     mov    ah,049h            ;e free memory block
  918.                     ;d Speicher freigeben
  919.     int    21h
  920. ;
  921. free_next:
  922.     mov    es,si
  923.     cmp    es:id,4dh        ;e normal block?
  924.                     ;d Normaler Block?
  925.     jne    free_ready        ;e ready if end of chain
  926.                     ;d Fertig wenn Ende der Kette
  927.     add    si,es:paras        ;e start + length
  928.                     ;d Beginn + Länge
  929.     inc    si            ;e next MCB
  930.                     ;d Nächster MCB
  931.     jmp    free_loop
  932. ;
  933. free_ready:
  934.     mov    ax,ds
  935.     mov    es,ax
  936. ;
  937. no_shrink:
  938.     mov    dx,filename        ;e params for exec
  939.                     ;d Parameter für EXEC
  940.     mov    bx,expar
  941.     mov    ax,04b00h
  942.     int    21h            ; exec
  943. ;>e
  944. ;    Return from EXEC system call. Don't count on any register except
  945. ;    CS to be restored (DOS 2.11 and previous versions killed all regs).
  946. ;<
  947. ;>d
  948. ;    Rückkehr vom EXEC Aufruf. Alle Register außer CS können zerstört
  949. ;    sein (DOS-Versionen 2.11 und früher zerstörten auch SS und SP).
  950. ;<
  951.     mov    bx,cs
  952.     mov    ds,bx
  953.     mov    es,bx
  954.     cli
  955.     mov    ss,bx
  956.     mov    sp,lmem spx
  957.     sti
  958.     cld
  959.     mov    lmem eretcode,ax    ;e save return code
  960.                     ;d Resultatcode sichern
  961.     pushf
  962.     pop    bx
  963.     mov    lmem retflags,bx    ;e and returned flags
  964.                     ;d und die gelieferten Flags
  965. ;
  966. ;e    Cancel Redirection
  967. ;d    Dateiumleitung aufheben
  968. ;
  969.     IF    REDIRECT
  970.     IF    NO_INHERIT
  971.     mov    si,lredirsav
  972.     mov    di,psp_handletab+5
  973.     mov    cx,3
  974.     rep movsw
  975.     ENDIF
  976.     mov    si,lstdinsav
  977.     xor    cx,cx
  978. ;
  979. lredirclose:
  980.     lodsw
  981.     cmp    ax,-1
  982.     je    lredclosenext
  983.     mov    bx,ax
  984.     mov    ah,46h
  985.     int    21h
  986. ;
  987. lredclosenext:
  988.     inc    cx
  989.     cmp    cx,3
  990.     jb    lredirclose
  991.     ENDIF
  992. ;
  993.     cmp    lmem lprep.swapmethod,0
  994.     je    exec_memok
  995.     jg    exec_expand
  996. ;
  997. ;    Terminate.
  998. ;
  999.     test    lmem retflags,1        ; carry?
  1000.     jnz    exec_term        ;e use EXEc retcode if set
  1001.                     ;d Resultat von EXEC liefern wenn ja
  1002.     mov    ah,4dh            ;e else get program return code
  1003.                     ;d Sonst Resultat von Programm holen
  1004.     int    21h
  1005. ;
  1006. exec_term:
  1007.     mov    ah,4ch
  1008.     int    21h
  1009. ;
  1010. ;
  1011. exec_expand:
  1012.     mov    ah,4ah            ; expand memory
  1013.     mov    bx,lmem lcurrdesc.msize
  1014.     int    21h
  1015.     jnc    exec_memok
  1016.     mov    ax,4cffh
  1017.     int    21h            ;e terminate on error
  1018.                     ;d Abbrechen bei Fehler
  1019. ;
  1020. ;e    Swap memory back
  1021. ;d    Zurücklesen Speicher
  1022. ;
  1023.     nop
  1024. ;
  1025. exec_memok:
  1026. ;
  1027. ;e    FALL THROUGH to the appropriate swap-in routine
  1028. ;d    Weiter in der passenden Einlagerungsroutine
  1029. ;
  1030. ;
  1031. getmcboff    =    offset get_mcb - offset lowcode_begin
  1032. iretoff        =    offset ireti - offset lowcode_begin
  1033. doexec_entry    =    offset doexec - offset lowcode_begin
  1034. base_length    =    offset $ - offset lowcode_begin
  1035. ;
  1036. ;-----------------------------------------------------------------------
  1037. ;>e
  1038. ;    The various swap in routines follow. Only one of the routines
  1039. ;    is copied to low memory.
  1040. ;    Note that the routines are never actually called, the EXEC return
  1041. ;    code falls through. The final RET thus will return to the restored
  1042. ;    memory image.
  1043. ;
  1044. ;    On entry, DS must point to low core.
  1045. ;    On exit to the restored code, DS is unchanged.
  1046. ;
  1047. ;
  1048. ;    swapin_ems:    swap in from EMS.
  1049. ;<
  1050. ;>d
  1051. ;    Es folgen die verschiedenen Wiederherstellungsroutinen. Nur 
  1052. ;    eine der Routinen wird in den residenten Teil kopiert.
  1053. ;    Beachten Sie, daß die Routinen nicht tatsächlich aufgerufen
  1054. ;    werden, der Code nach dem EXEC-Aufruf läuft in sie hinein. Das
  1055. ;    abschließende RET kehrt daher in das wiederhergestellte Haupt-
  1056. ;    programm zurück.
  1057. ;
  1058. ;    Bei Einsprung zeight DS auf den Basis-PSP.
  1059. ;    Bei Rückkehr in das wiederhergestellte Programm ist DS unverändert.
  1060. ;
  1061. ;
  1062. ;    swapin_ems:    Wiederherstellen von EMS.
  1063. ;<
  1064. swapin_ems    proc    far
  1065. ;
  1066.     xor    bx,bx
  1067.     mov    si,ems_parasize
  1068.     mov    dx,lmem lprep.handle    ; EMS handle
  1069. ;
  1070. swinems_main:
  1071.     push    ds
  1072.     mov    cx,lmem lcurrdesc.swsize    ;e block length in paras
  1073.                         ;d Blocklänge in Paragraphen
  1074.     mov    di,lmem lcurrdesc.swoffset    ;e swap offset
  1075.                         ;d Lese-Offset
  1076.     mov    es,lmem lcurrdesc.addr        ;e segment to swap
  1077.                         ;d Lese-Segment
  1078.     mov    ds,lmem lprep.ems_pageframe    ; page frame address
  1079. ;
  1080.     mov    ax,ems_parasize        ;e max length
  1081.                     ;d Maximale Länge
  1082.     sub    ax,si            ;e minus current offset
  1083.                     ;d Minus laufender Offset
  1084.     jnz    swinems_ok        ;e go copy if nonzero
  1085.                     ;d Kopieren wenn nicht 0
  1086. ;
  1087. swinems_loop:
  1088.     mov    ax,4400h        ;e map in next page
  1089.                     ;d Nächste EMS-Page einmappen
  1090.     int    EMM_INT
  1091.     or    ah,ah
  1092.     jnz    swinems_error
  1093.     mov    si,0            ;e reset offset
  1094.                     ;d Offset zurücksetzen
  1095.     inc    bx            ;e bump up page number
  1096.                     ;d Seitennummer erhöhen
  1097.     mov    ax,ems_parasize        ;e max length to copy
  1098.                     ;d Maximale Länge
  1099. ;
  1100. swinems_ok:
  1101.     cmp    ax,cx            ;e length to copy
  1102.                     ;d zu kopierende Länge
  1103.     jbe    swinems_doit        ;e go do it if <= total length
  1104.                     ;d kopieren wenn <= Gesamtlänge
  1105.     mov    ax,cx            ;e else use total length
  1106.                     ;d sonst Gesamtlänge kopieren
  1107. ;
  1108. swinems_doit:
  1109.     sub    cx,ax            ;e subtract copy length from total
  1110.                     ;d Gesamtlänge -= kopierte Länge
  1111.     push    cx            ;e and save
  1112.                     ;d sichern
  1113.     push    ax            ;e save the copy length in paras
  1114.                     ;d Sichern Kopierlänge in Paragraphen
  1115.     push    si
  1116.     push    di
  1117.     mov    cl,3
  1118.     shl    ax,cl            ;e convert to number of words (!)
  1119.                     ;d Konvertieren in Anzahl Worte (!)
  1120.     inc    cl
  1121.     shl    si,cl            ;e convert to byte address
  1122.                     ;d In Byte-Adresse konvertieren
  1123.     mov    cx,ax
  1124.     rep movsw
  1125.     pop    di
  1126.     pop    si
  1127.     pop    cx            ;e copy length in paras
  1128.                     ;d Kopierlänge in Paragraphen
  1129.     mov    ax,es
  1130.     add    ax,cx            ;e add copy length to dest segment
  1131.                     ;d Kopierlänge auf Zielsegment
  1132.     add    si,cx            ;e and EMS page offset
  1133.                     ;d und EMS-Seiten-Offset addieren
  1134.     mov    es,ax
  1135.     pop    cx            ;e remaining length
  1136.                     ;d Restlänge
  1137.     or    cx,cx            ;e did we copy everything?
  1138.                     ;d Alles kopiert?
  1139.     jnz    swinems_loop        ;e go loop if not
  1140.                     ;d Nochmal wenn nein
  1141. ;
  1142.     pop    ds
  1143.     cmp    lmem lcurrdesc.num_follow,0    ;e another MCB?
  1144.                         ;d noch ein MCB?
  1145.     je    swinems_complete    ;e exit if not
  1146.                     ;d Fertig wenn nein
  1147. ;
  1148. ;e    Another MCB follows, read next mcb descriptor into currdesc
  1149. ;d    Ein weiterer MCB folgt, lesen MCB Deskriptor nach currdesc
  1150. ;
  1151.     cmp    si,ems_parasize
  1152.     jb    swinems_nonewpage    ;e no new block needed
  1153.                     ;d kein neuer Block nötig
  1154.     mov    ax,4400h        ; map page, phys = 0
  1155.     int    EMM_INT
  1156.     or    ah,ah
  1157.     jnz    swinems_error1
  1158.     mov    si,0
  1159.     inc    bx
  1160. ;
  1161. swinems_nonewpage:
  1162.     push    si
  1163.     push    ds
  1164.     mov    ax,ds
  1165.     mov    es,ax
  1166.     mov    ds,lmem lprep.ems_pageframe    ; page frame address
  1167.     mov    cl,4
  1168.     shl    si,cl            ;e convert to byte address
  1169.                     ;d in Byte-Adresse konvertieren
  1170.     mov    cx,TYPE mcbdesc
  1171.     mov    di,lcurrdesc
  1172.     rep movsb
  1173.     pop    ds
  1174.     pop    si
  1175.     inc    si            ;e one paragraph
  1176.                     ;d Einen Paragraphen
  1177. ;
  1178.     push    bx
  1179.     call    lmem cgetmcb
  1180.     pop    bx
  1181.     jc    swinems_error1
  1182.     jmp    swinems_main
  1183. ;
  1184. swinems_complete:
  1185.     mov    ah,45h            ;e release EMS pages
  1186.                     ;d Freigeben EMS-Speicher
  1187.     int    EMM_INT
  1188.     ret
  1189. ;
  1190. swinems_error:
  1191.     pop    ds
  1192. swinems_error1:
  1193.     mov    ah,45h            ;e release EMS pages on error
  1194.                     ;d Bei Fehler EMS freigeben
  1195.     int    EMM_INT
  1196.     mov    ax,4cffh
  1197.     int    21h            ; terminate
  1198. ;
  1199. swapin_ems    endp
  1200. ;
  1201. swinems_length    = offset $ - offset swapin_ems
  1202. ;
  1203. ;
  1204. ;e    swapin_xms:    swap in from XMS.
  1205. ;d    swapin_xms:    Wiederherstellen von XMS.
  1206. ;
  1207. swapin_xms    proc    far
  1208. ;
  1209.     mov    ax,lmem lprep.handle    ; XMS handle
  1210.     mov    lmem lxmsctl.srchnd,ax     ;e source is XMS
  1211.                     ;d Quelle ist XMS
  1212.     mov    lmem lxmsctl.desthnd,0     ;e dest is normal memory
  1213.                     ;d Ziel ist Standardspeicher
  1214.     mov    lmem lxmsctl.srclo,0
  1215.     mov    lmem lxmsctl.srchi,0
  1216. ;
  1217. swinxms_main:
  1218.     mov    ax,lmem lcurrdesc.swsize ;e size in paragraphs
  1219.                      ;d Größe in Paragraphen
  1220.     mov    cl,4
  1221.     rol    ax,cl            ;e size in bytes + high nibble
  1222.                     ;d Größe in Bytes + high nibble
  1223.     mov    dx,ax
  1224.     and    ax,0fff0h        ; low word
  1225.     and    dx,0000fh        ; high word
  1226.     mov    lmem lxmsctl.lenlo,ax    ;e into control block
  1227.                     ;d in den Kontrollblock
  1228.     mov    lmem lxmsctl.lenhi,dx
  1229.     mov    ax,lmem lcurrdesc.swoffset    ;e swap offset
  1230.                         ;d Lese-Offset
  1231.     mov    lmem lxmsctl.destlo,ax         ;e into control block
  1232.                         ;d in den Kontrollblock
  1233.     mov    ax,lmem lcurrdesc.addr        ;e segment to swap
  1234.                         ;d Lese-Segment
  1235.     mov    lmem lxmsctl.desthi,ax
  1236.     mov    si,lxmsctl
  1237.     mov    ah,0bh
  1238.     call    lmem lprep.xmm        ; move it
  1239.     or    ax,ax
  1240.     jz    swinxms_error
  1241.     mov    ax,lmem lxmsctl.lenlo    ;e adjust source addr
  1242.                     ;d Quelladresse adjustieren
  1243.     add    lmem lxmsctl.srclo,ax
  1244.     mov    ax,lmem lxmsctl.lenhi
  1245.     adc    lmem lxmsctl.srchi,ax
  1246. ;
  1247.     cmp    lmem lcurrdesc.num_follow,0    ;e another MCB?
  1248.                         ;d noch ein MCB?
  1249.     je    swinxms_complete
  1250. ;
  1251.     mov    lmem lxmsctl.lenlo,TYPE mcbdesc
  1252.     mov    lmem lxmsctl.lenhi,0
  1253.     mov    lmem lxmsctl.desthi,ds
  1254.     mov    lmem lxmsctl.destlo,lcurrdesc
  1255.     mov    si,lxmsctl
  1256.     mov    ah,0bh
  1257.     call    lmem lprep.xmm        ; move it
  1258.     or    ax,ax
  1259.     jz    swinxms_error
  1260.     add    lmem lxmsctl.srclo,16    ; one paragraph
  1261.     adc    lmem lxmsctl.srchi,0
  1262. ;
  1263.     call    lmem cgetmcb
  1264.     jc    swinxms_error
  1265.     jmp    swinxms_main
  1266. ;
  1267. swinxms_complete:
  1268.     mov    ah,0ah            ;e release XMS frame
  1269.                     ;d Freigeben XMS-Speicher
  1270.     mov    dx,lmem lprep.handle       ; XMS handle
  1271.     call    lmem lprep.xmm
  1272.     ret
  1273. ;
  1274. swinxms_error:
  1275.     mov    ah,0ah            ;e release XMS frame on error
  1276.                     ;d Bei Fehler XMS-Speicher freigeben
  1277.     call    lmem lprep.xmm
  1278.     mov    ax,4c00h
  1279.     int    21h
  1280. ;
  1281. swapin_xms    endp
  1282. ;
  1283. swinxms_length    = offset $ - offset swapin_xms
  1284. ;
  1285. ;
  1286. ;e    swapin_file:    swap in from file.
  1287. ;d    swapin_file:    Wiederherstellen von Datei.
  1288. ;
  1289. swapin_file    proc    far
  1290. ;
  1291.     mov    dx,lprep.swapfilename
  1292.     mov    ax,3d00h            ; open file
  1293.     int    21h
  1294.     jc    swinfile_error2
  1295.     mov    bx,ax                ; file handle
  1296. ;
  1297. swinfile_main:
  1298.     push    ds
  1299.     mov    cx,lmem lcurrdesc.swsize    ;e size in paragraphs
  1300.                         ;d Blocklänge in Paragraphen
  1301.     mov    dx,lmem lcurrdesc.swoffset    ; swap offset
  1302.     mov    ds,lmem lcurrdesc.addr        ; segment to swap
  1303. ;
  1304. swinfile_loop:
  1305.     mov    ax,cx
  1306.     cmp    ah,8h            ;e above 32k?
  1307.                     ;d mehr als 32k?
  1308.     jbe    swinfile_ok        ;e go read if not
  1309.                     ;d lesen wenn nein
  1310.     mov    ax,800h            ;e else read 32k
  1311.                     ;d sonst 32k lesen
  1312. ;
  1313. swinfile_ok:
  1314.     sub    cx,ax            ;e remaining length
  1315.                     ;d Restlänge
  1316.     push    cx            ;e save it
  1317.                     ;d sichern
  1318.     push    ax            ;e and save paras to read
  1319.                     ;d Sichern Länge in Paragraphen
  1320.     mov    cl,4
  1321.     shl    ax,cl            ;e convert to bytes
  1322.                     ;d Konvertieren in Anzahl Bytes
  1323.     mov    cx,ax
  1324.     mov    ah,3fh            ; read
  1325.     int    21h
  1326.     jc    swinfile_error
  1327.     cmp    ax,cx
  1328.     jne    swinfile_error
  1329.     pop    cx            ;e paras read
  1330.                     ;d Gelesene Paragraphen
  1331.     mov    ax,ds
  1332.     add    ax,cx            ;e bump up dest segment
  1333.                     ;d Add. Kopierlänge auf Zielsegment
  1334.     mov    ds,ax
  1335.     pop    cx            ;e remaining length
  1336.                     ;d Restlänge
  1337.     or    cx,cx            ;e anything left?
  1338.                     ;d Noch etwas übrig?
  1339.     jnz    swinfile_loop        ;e go loop if yes
  1340.                     ;d Nochmal wenn ja
  1341. ;
  1342.     pop    ds
  1343.     cmp    lmem lcurrdesc.num_follow,0    ; another MCB?
  1344.                         ;d noch ein MCB?
  1345.     je    swinfile_complete    ;e ready if not
  1346.                     ;d Fertig wenn nein
  1347.     mov    cx,16            ;e read one paragraph
  1348.                     ;d einen Paragraphen lesen
  1349.     mov    dx,lcurrdesc
  1350.     mov    ah,3fh
  1351.     int    21h
  1352.     jc    swinfile_error1
  1353.     cmp    ax,cx
  1354.     jne    swinfile_error1
  1355. ;
  1356.     push    bx
  1357.     call    lmem cgetmcb
  1358.     pop    bx
  1359.     jc    swinfile_error1
  1360.     jmp    swinfile_main
  1361. ;
  1362. ;
  1363. swinfile_complete:
  1364.     mov    ah,3eh            ; close file
  1365.     int    21h
  1366.     mov    dx,lprep.swapfilename
  1367.     mov    ah,41h            ; delete file
  1368.     int    21h
  1369.     ret
  1370. ;
  1371. swinfile_error:
  1372.     pop    cx
  1373.     pop    cx
  1374.     pop    ds
  1375. swinfile_error1:
  1376.     mov    ah,3eh            ; close file
  1377.     int    21h
  1378. swinfile_error2:
  1379.     mov    dx,lprep.swapfilename
  1380.     mov    ah,41h            ; delete file
  1381.     int    21h
  1382.     mov    ax,4cffh
  1383.     int    21h
  1384. ;
  1385. swapin_file    endp
  1386. ;
  1387. swinfile_length    = offset $ - offset swapin_file
  1388. ;
  1389. ;
  1390. ;e    swapin_none:    no swap, return immediately.
  1391. ;d    swapin_none:    Kein Wiederherstellen, nur Rückkehr.
  1392. ;
  1393. swapin_none    proc    far
  1394. ;
  1395.     ret
  1396. ;
  1397. swapin_none    endp
  1398. ;
  1399. ;
  1400.     IF    swinems_length GT swinxms_length
  1401. swcodelen    =    swinems_length
  1402.     ELSE
  1403. swcodelen    =    swinxms_length
  1404.     ENDIF
  1405.     IF    swinfile_length GT swcodelen
  1406. swcodelen    =    swinfile_length
  1407.     ENDIF
  1408. ;
  1409. swap_codelen    =    ((swcodelen + 1) / 2) * 2
  1410. ;
  1411. codelen        =    base_length + swap_codelen
  1412. reslen        =    codebeg + codelen
  1413. keep_paras    =    (reslen + 15) shr 4    ;e paragraphs to keep
  1414.                         ;d Residente Paragraphen
  1415. swapbeg        =    keep_paras shl 4    ;e start of swap space
  1416.                         ;d Beginn Auslagerungsbereich
  1417. savespace    =    swapbeg - 5ch    ;e length of overwritten area
  1418.                     ;d Länge überschriebener Bereich
  1419. ;
  1420. ;--------------------------------------------------------------------
  1421. ;
  1422.     IFDEF    PASCAL
  1423.     .data
  1424.     extrn    swap_prep: prep_block
  1425.     ELSE
  1426.     IFDEF    TC_HUGE
  1427.     .fardata?    my_data
  1428.     assume    ds:my_data
  1429.     ELSE
  1430.     .data?
  1431.     ENDIF
  1432.     ENDIF
  1433. ;
  1434. ;>e
  1435. ;    Space for saving the part of the memory image below the
  1436. ;    swap area that is overwritten by our code.
  1437. ;<
  1438. ;>d
  1439. ;    Platz zum Sichern des Teils des Speichers der vom 
  1440. ;    Aus-/Einlagerungscode und den Variablen überschrieben wird.
  1441. ;<
  1442. save_dat    db    savespace dup(?)
  1443. ;>e
  1444. ;    Variables used while swapping out.
  1445. ;    The "swap_prep" structure is initialized by prep_swap.
  1446. ;<
  1447. ;>d
  1448. ;    Variablen zur Benutzung beim Auslagern.
  1449. ;    Die "swap_prep" Struktur wird durch prep_swap initialisiert.
  1450. ;<
  1451.     IFNDEF    PASCAL
  1452. swap_prep    prep_block    <>
  1453.     ENDIF
  1454. nextmcb        mcbdesc        <>
  1455. currdesc    mcbdesc        <>
  1456. xmsctl        xms_control    <>
  1457. ems_curpage    dw        ?    ;e current EMS page number
  1458.                     ;d Laufende Nummer EMS-Seite
  1459. ems_curoff    dw        ?    ;e current EMS offset (paragraph)
  1460.                     ;d Laufender EMS Offset (Paragraph)
  1461. ;
  1462. ;--------------------------------------------------------------------
  1463. ;       
  1464.     .code
  1465. ;>e
  1466. ;    swapout_ems:    swap out an MCB block to EMS.
  1467. ;
  1468. ;    Entry:    "currdesc"     contains description of block to swap
  1469. ;        "nextmcb"    contains MCB-descriptor of next block
  1470. ;                if currdesc.num_follow is nonzero
  1471. ;
  1472. ;    Exit:    0 if OK, != 0 if error, Zero-flag set accordingly.
  1473. ;
  1474. ;    Uses:    All regs excpt DS
  1475. ;<
  1476. ;>d
  1477. ;    swapout_ems:    Auslagern eines MCB nach EMS.
  1478. ;
  1479. ;    Ein:    "currdesc"     Beschreibung des auszulagernden Blocks
  1480. ;        "nextmcb"    MCB-Deskriptor des nächsten Blocks
  1481. ;                wenn currdesc.num_follow nicht 0 ist.
  1482. ;
  1483. ;    Aus:    0 wenn OK, != 0 bei Fehler, Zero-flag entsprechend gesetzt.
  1484. ;
  1485. ;    Benutzt: Alle Register außer DS
  1486. ;<
  1487. swapout_ems    proc    near
  1488. ;
  1489.     push    ds
  1490.     mov    cx,currdesc.swsize    ;e block length in paras
  1491.                     ;d Blocklänge in Paragraphen
  1492.     mov    si,currdesc.swoffset    ; swap offset
  1493.     mov    dx,swap_prep.handle    ; EMS handle
  1494.     mov    bx,ems_curpage        ;e current EMS page
  1495.                     ;d laufende EMS Seite
  1496.     mov    di,ems_curoff        ;e current EMS page offset (paras)
  1497.                     ;d laufender EMS Offset (Paragraph)
  1498.     mov    es,swap_prep.ems_pageframe    ; page frame address
  1499.     mov    ds,currdesc.addr    ; segment to swap
  1500. ;
  1501.     mov    ax,ems_parasize        ;e max length
  1502.                     ;d Maximale Länge
  1503.     sub    ax,di            ;e minus current offset
  1504.                     ;d Minus laufender Offset
  1505.     jnz    swems_ok        ;e go copy if there's room
  1506.                     ;d Kopieren wenn noch Platz ist
  1507. ;
  1508. swems_loop:
  1509.     mov    ax,4400h        ;e map in next page
  1510.                     ;d Nächste EMS-Page einmappen
  1511.     int    EMM_INT
  1512.     or    ah,ah
  1513.     jnz    swems_error
  1514.     mov    di,0            ;e reset offset
  1515.                     ;d Offset zurücksetzen
  1516.     inc    bx            ;e bump up page number
  1517.                     ;d Seitennummer erhöhen
  1518.     mov    ax,ems_parasize        ;e max length to copy
  1519.                     ;d Maximale Länge
  1520. ;
  1521. swems_ok:
  1522.     cmp    ax,cx            ;e length to copy
  1523.                     ;d zu kopierende Länge
  1524.     jbe    swems_doit        ;e go do it if <= total length
  1525.                     ;d kopieren wenn <= Gesamtlänge
  1526.     mov    ax,cx            ;e else use total length
  1527.                     ;d sonst Gesamtlänge kopieren
  1528. ;
  1529. swems_doit:
  1530.     sub    cx,ax            ;e subtract copy length from total
  1531.                     ;d Gesamtlänge -= kopierte Länge
  1532.     push    cx            ;e and save
  1533.                     ;d sichern
  1534.     push    ax            ;e save the copy length in paras
  1535.                     ;d Sichern Kopierlänge in Paragraphen
  1536.     push    si
  1537.     push    di
  1538.     mov    cl,3
  1539.     shl    ax,cl            ;e convert to number of words (!)
  1540.                     ;d Konvertieren in Anzahl Worte (!)
  1541.     inc    cl
  1542.     shl    di,cl            ;e convert to byte address
  1543.                     ;d In Byte-Adresse konvertieren
  1544.     mov    cx,ax
  1545.     rep movsw
  1546.     pop    di
  1547.     pop    si
  1548.     pop    cx            ;e copy length in paras
  1549.                     ;d Kopierlänge in Paragraphen
  1550.     mov    ax,ds
  1551.     add    ax,cx            ;e add copy length to source segment
  1552.                     ;d Kopierlänge auf Zielsegment
  1553.     add    di,cx            ;e and EMS page offset
  1554.                     ;d und EMS-Seiten-Offset addieren
  1555.     mov    ds,ax
  1556.     pop    cx            ;e remaining length
  1557.                     ;d Restlänge
  1558.     or    cx,cx            ;e did we copy everything?
  1559.                     ;d Alles kopiert?
  1560.     jnz    swems_loop        ;e go loop if not
  1561.                     ;d Nochmal wenn nein
  1562. ;
  1563.     pop    ds
  1564.     cmp    currdesc.num_follow,0    ;e another MCB?
  1565.                     ;d noch ein MCB?
  1566.     je    swems_complete        ;e exit if not
  1567.                     ;d Fertig wenn nein
  1568. ;
  1569. ;e    Another MCB follows, append nextmcb to save block.
  1570. ;d    Ein weiterer MCB folgt, nextmcb an Block anfügen.
  1571. ;
  1572.     cmp    di,ems_parasize
  1573.     jb    swems_nonewpage        ;e no new block needed
  1574.                     ;d kein neuer Block nötig
  1575.     mov    ax,4400h        ; map page, phys = 0
  1576.     int    EMM_INT
  1577.     or    ah,ah
  1578.     jnz    swems_error1
  1579.     mov    di,0
  1580.     inc    bx
  1581. ;
  1582. swems_nonewpage:
  1583.     push    di
  1584.     mov    cl,4
  1585.     shl    di,cl            ;e convert to byte address
  1586.                     ;d in Byte-Adresse konvertieren
  1587.     mov    cx,TYPE mcbdesc
  1588.     mov    si,offset nextmcb
  1589.     rep movsb
  1590.     pop    di
  1591.     inc    di            ;e one paragraph
  1592.                     ;d Einen Paragraphen
  1593. ;
  1594. swems_complete:
  1595.     mov    ems_curpage,bx
  1596.     mov    ems_curoff,di
  1597.     xor    ax,ax
  1598.     ret
  1599. ;
  1600. swems_error:
  1601.     pop    ds
  1602. swems_error1:
  1603.     mov    ah,45h            ;e release EMS pages on error
  1604.                     ;d Bei Fehler EMS freigeben
  1605.     int    EMM_INT
  1606.     mov    ax,RC_SWAPERROR
  1607.     or    ax,ax
  1608.     ret
  1609. ;
  1610. swapout_ems    endp
  1611. ;
  1612. ;>e
  1613. ;    swapout_xms:    swap out an MCB block to XMS.
  1614. ;
  1615. ;    Entry:    "currdesc"     contains description of block to swap
  1616. ;        "nextmcb"    contains MCB-descriptor of next block
  1617. ;                if currdesc.num_follow is nonzero
  1618. ;
  1619. ;    Exit:    0 if OK, -1 if error, Zero-flag set accordingly.
  1620. ;
  1621. ;    Uses:    All regs excpt DS
  1622. ;<
  1623. ;>d
  1624. ;    swapout_xms:    Auslagern eines MCB nach XMS.
  1625. ;
  1626. ;    Ein:    "currdesc"     Beschreibung des auszulagernden Blocks
  1627. ;        "nextmcb"    MCB-Deskriptor des nächsten Blocks
  1628. ;                wenn currdesc.num_follow nicht 0 ist.
  1629. ;
  1630. ;    Aus:    0 wenn OK, != 0 bei Fehler, Zero-flag entsprechend gesetzt.
  1631. ;
  1632. ;    Benutzt: Alle Register außer DS
  1633. ;<
  1634. swapout_xms    proc    near
  1635. ;
  1636.     push    ds
  1637.     pop    es
  1638.     mov    ax,currdesc.swsize    ;e size in paragraphs
  1639.                     ;d Größe in Paragraphen
  1640.     mov    cl,4
  1641.     rol    ax,cl            ;e size in bytes + high nibble
  1642.                     ;d Größe in Bytes + high nibble
  1643.     mov    dx,ax
  1644.     and    ax,0fff0h        ; low word
  1645.     and    dx,0000fh        ; high word
  1646.     mov    xmsctl.lenlo,ax        ; into control block
  1647.     mov    xmsctl.lenhi,dx
  1648.     mov    xmsctl.srchnd,0        ;e source is normal memory
  1649.                     ;d Quelle ist Standardspeicher
  1650.     mov    ax,currdesc.swoffset    ; swap offset
  1651.     mov    xmsctl.srclo,ax        ; into control block
  1652.     mov    ax,currdesc.addr    ; segment to swap
  1653.     mov    xmsctl.srchi,ax
  1654.     mov    ax,swap_prep.handle    ; XMS handle
  1655.     mov    xmsctl.desthnd,ax
  1656.     mov    si,offset xmsctl
  1657.     mov    ah,0bh
  1658.     call    swap_prep.xmm        ; move it
  1659.     or    ax,ax
  1660.     jz    swxms_error
  1661.     mov    ax,xmsctl.lenlo        ;e adjust destination addr
  1662.                     ;d Zieladresse adjustieren
  1663.     add    xmsctl.destlo,ax
  1664.     mov    ax,xmsctl.lenhi
  1665.     adc    xmsctl.desthi,ax
  1666. ;
  1667.     cmp    currdesc.num_follow,0    ;e another MCB?
  1668.                     ;d noch ein MCB?
  1669.     je    swxms_complete
  1670. ;
  1671.     mov    xmsctl.lenlo,TYPE mcbdesc
  1672.     mov    xmsctl.lenhi,0
  1673.     mov    xmsctl.srchi,ds
  1674.     mov    xmsctl.srclo,offset nextmcb
  1675.     mov    si,offset xmsctl
  1676.     mov    ah,0bh
  1677.     call    swap_prep.xmm        ; move it
  1678.     or    ax,ax
  1679.     jz    swxms_error
  1680.     add    xmsctl.destlo,16    ; one paragraph
  1681.     adc    xmsctl.desthi,0
  1682. ;
  1683. swxms_complete:
  1684.     xor    ax,ax
  1685.     ret
  1686. ;
  1687. swxms_error:
  1688.     mov    ah,0ah            ;e release XMS frame on error
  1689.                     ;d Bei Fehler XMS-Speicher freigeben
  1690.     mov    dx,swap_prep.handle    ; XMS handle
  1691.     call    swap_prep.xmm
  1692.     mov    ax,RC_SWAPERROR
  1693.     or    ax,ax
  1694.     ret
  1695. ;
  1696. swapout_xms    endp
  1697. ;
  1698. ;>e
  1699. ;    swapout_file:    swap out an MCB block to file.
  1700. ;
  1701. ;    Entry:    "currdesc"     contains description of block to swap
  1702. ;        "nextmcb"    contains MCB-descriptor of next block
  1703. ;                if currdesc.num_follow is nonzero
  1704. ;
  1705. ;    Exit:    0 if OK, -1 if error, Zero-flag set accordingly.
  1706. ;
  1707. ;    Uses:    All regs excpt DS
  1708. ;<
  1709. ;>d
  1710. ;    swapout_file:    Auslagern eines MCB auf Datei.
  1711. ;
  1712. ;    Ein:    "currdesc"     Beschreibung des auszulagernden Blocks
  1713. ;        "nextmcb"    MCB-Deskriptor des nächsten Blocks
  1714. ;                wenn currdesc.num_follow nicht 0 ist.
  1715. ;
  1716. ;    Aus:    0 wenn OK, != 0 bei Fehler, Zero-flag entsprechend gesetzt.
  1717. ;
  1718. ;    Benutzt: Alle Register außer DS
  1719. ;<
  1720. swapout_file    proc    near
  1721. ;
  1722.     push    ds
  1723.     mov    cx,currdesc.swsize    ;e size in paragraphs
  1724.                     ;d Blocklänge in Paragraphen
  1725.     mov    bx,swap_prep.handle    ; file handle
  1726.     mov    dx,currdesc.swoffset    ; swap offset
  1727.     mov    ds,currdesc.addr    ; segment to swap
  1728. ;
  1729. swfile_loop:
  1730.     mov    ax,cx
  1731.     cmp    ah,8h            ;e above 32k?
  1732.                     ;d mehr als 32k?
  1733.     jbe    swfile_ok        ;e go write if not
  1734.                     ;d schreiben wenn nein
  1735.     mov    ax,800h            ;e else write 32k
  1736.                     ;d sonst 32k schreiben
  1737. ;
  1738. swfile_ok:
  1739.     sub    cx,ax            ;e remaining length
  1740.                     ;d Restlänge
  1741.     push    cx            ;e save it
  1742.                     ;d sichern
  1743.     push    ax            ;e and save paras to write
  1744.                     ;d Sichern Länge in Paragraphen
  1745.     mov    cl,4
  1746.     shl    ax,cl            ;e convert to bytes
  1747.                     ;d Konvertieren in Anzahl Bytes
  1748.     mov    cx,ax
  1749.     mov    ah,40h            ; write
  1750.     int    21h
  1751.     jc    swfile_error
  1752.     cmp    ax,cx
  1753.     jne    swfile_error
  1754.     pop    cx            ;e paras written
  1755.                     ;d Geschriebene Paragraphen
  1756.     mov    ax,ds
  1757.     add    ax,cx            ;e bump up source segment
  1758.                     ;d Add. Kopierlänge auf Quellsegment
  1759.     mov    ds,ax
  1760.     pop    cx            ;e remaining length
  1761.                     ;d Restlänge
  1762.     or    cx,cx            ;e anything left?
  1763.                     ;d Noch etwas übrig?
  1764.     jnz    swfile_loop        ;e go loop if yes
  1765.                     ;d Nochmal wenn ja
  1766. ;
  1767.     pop    ds
  1768.     cmp    currdesc.num_follow,0    ;e another MCB?
  1769.                     ;d noch ein MCB?
  1770.     je    swfile_complete        ;e ready if not
  1771.                     ;d Fertig wenn nein
  1772.     mov    cx,16            ;e write one paragraph
  1773.                     ;d einen Paragraphen schreiben
  1774.     mov    dx,offset nextmcb
  1775.     mov    ah,40h
  1776.     int    21h
  1777.     jc    swfile_error1
  1778.     cmp    ax,cx
  1779.     jne    swfile_error1
  1780. ;
  1781. swfile_complete:
  1782.     xor    ax,ax
  1783.     ret
  1784. ;
  1785. swfile_error:
  1786.     pop    cx
  1787.     pop    cx
  1788.     pop    ds
  1789. swfile_error1:
  1790.     mov    ah,3eh            ; close file
  1791.     int    21h
  1792.     mov    dx,offset swap_prep.swapfilename
  1793.     mov    ah,41h            ; delete file
  1794.     int    21h
  1795.     mov    ax,RC_SWAPERROR
  1796.     or    ax,ax
  1797.     ret
  1798. ;
  1799. swapout_file    endp
  1800. ;
  1801. ;--------------------------------------------------------------------------
  1802. ;
  1803.     IF    REDIRECT
  1804. ;>e
  1805. ;    @redirect: Redirect a file.
  1806. ;
  1807. ;    Entry:    DS:SI = Filename pointer
  1808. ;        AX zero if filename is NULL
  1809. ;        CX    = Handle to redirect
  1810. ;        ES:DI = Handle save pointer
  1811. ;
  1812. ;    Exit:    Carry set on error, then AL has DOS error code
  1813. ;        ES:DI updated
  1814. ;
  1815. ;    Uses:    AX,BX,DX,SI
  1816. ;<
  1817. ;>d
  1818. ;    @redirect: Umleiten einer Datei.
  1819. ;
  1820. ;    Entry:    DS:SI = Zeiger auf Dateinamen
  1821. ;        AX ist 0 wenn Dateinamenszeiger NULL ist
  1822. ;        CX    = Umzuleitendes Handle
  1823. ;        ES:DI = Zeiger auf Handle-Sicherungswort
  1824. ;
  1825. ;    Exit:    Carry gesetzt bei Fehler, dann ist AL=DOS-Fehlercode
  1826. ;        ES:DI wird modifiziert.
  1827. ;
  1828. ;    Uses:    AX,BX,DX,SI
  1829. ;<
  1830. @redirect    proc    near
  1831.         local    doserr
  1832. ;
  1833.     or    ax,ax
  1834.     jz    no_redirect
  1835.     cmp    byte ptr [si],0
  1836.     jne    do_redirect
  1837. ;
  1838. no_redirect:
  1839.     mov    ax,-1
  1840.     stosw
  1841.     ret
  1842. ;
  1843. do_redirect:
  1844.     IFDEF    PASCAL
  1845.     inc    si            ;e skip length byte
  1846.                     ;d Längenbyte überspringen
  1847.     ENDIF
  1848.     or    cx,cx
  1849.     jnz    redir_write
  1850.     mov    dx,si
  1851.     mov    ax,3d00h    ; open file, read only
  1852.     int    21h
  1853.     mov    doserr,ax
  1854.     jc    redir_failed
  1855. ;
  1856. redir_ok:
  1857.     mov    dx,ax
  1858.     mov    ah,45h        ; duplicate handle
  1859.     mov    bx,cx
  1860.     int    21h
  1861.     mov    doserr,ax
  1862.     jc    redir_failed_dup
  1863.     push    ax
  1864.     mov    bx,dx
  1865.     mov    ah,46h        ; force duplicate handle
  1866.     int    21h
  1867.     mov    doserr,ax
  1868.     pop    ax
  1869.     jc    redir_failed_force
  1870.     stosw
  1871.     mov    ah,3eh        ; close file
  1872.     int    21h
  1873.     clc
  1874.     ret
  1875. ;
  1876. redir_failed_force:
  1877.     mov    bx,ax
  1878.     mov    ah,3eh        ; close file
  1879.     int    21h
  1880. ;
  1881. redir_failed_dup:
  1882.     mov    bx,dx
  1883.     mov    ah,3eh        ; close file
  1884.     int    21h
  1885. ;
  1886. redir_failed:
  1887.     mov    ax,doserr
  1888.     stc
  1889.     ret
  1890. ;
  1891. redir_write:
  1892.     cmp    byte ptr [si],'>'
  1893.     jne    no_append
  1894.     inc    si
  1895.     mov    dx,si
  1896.     mov    ax,3d02h        ; open file, read/write
  1897.     int    21h
  1898.     jc    no_append
  1899.     mov    bx,ax
  1900.     push    cx
  1901.     mov    ax,4202h        ; move file, offset from EOF
  1902.     xor    cx,cx
  1903.     mov    dx,cx
  1904.     int    21h
  1905.     mov    doserr,ax
  1906.     pop    cx
  1907.     mov    ax,bx
  1908.     jnc    redir_ok
  1909.     mov    dx,ax
  1910.     jmp    redir_failed_dup
  1911. ;
  1912. no_append:
  1913.     mov    dx,si
  1914.     mov    ah,3ch
  1915.     push    cx
  1916.     xor    cx,cx
  1917.     int    21h
  1918.     mov    doserr,ax
  1919.     pop    cx
  1920.     jc    redir_failed
  1921.     jmp    redir_ok
  1922. ;
  1923. @redirect    endp
  1924. ;
  1925.     ENDIF
  1926. ;
  1927. ;--------------------------------------------------------------------------
  1928. ;
  1929.     IFDEF    PASCAL
  1930.     IF    PAS_FREE
  1931. ;
  1932. ;e    @freepas: Chain unused Pascal Heap into DOS free list.
  1933. ;d    @freepas: Den unbenutzten Pascal Heap in die DOS Freiliste einfügen.
  1934. ;
  1935. @freepas    proc    near
  1936. ;
  1937.     mov    swap_prep.pmemid,0    ;e Init to no free block
  1938.                     ;d Init auf keinen freien Block
  1939. ;>e
  1940. ;    Load pointer to end of unused heap. For TP 5.x, this is
  1941. ;    FreePtr (which has to be adjusted if the offset part is 0).
  1942. ;    For TP 6.x, it is HeapEnd.
  1943. ;    For both versions, there may be data located after this
  1944. ;    pointer, so we may have to create an MCB.
  1945. ;<
  1946. ;>d
  1947. ;    Zeiger auf Ende des unbenutzten Heap laden. Für TP 5.x, der Zeiger
  1948. ;    ist FreePtr (muß adjustiert werden wenn der Offset-Teil 0 ist).
  1949. ;    Für TP 6.x ist es HeapEnd.
  1950. ;    Für beide Versionen können nach diesem Zeiger noch Daten folgen,
  1951. ;    sodaß eventuell ein MCB erzeugt werden muß.
  1952. ;<
  1953.     IF    TPAS_6
  1954.     mov    ax,word ptr HeapEnd
  1955.     mov    dx,word ptr HeapEnd+2
  1956.     ELSE
  1957.     mov    ax,word ptr FreePtr
  1958.     mov    dx,word ptr FreePtr+2
  1959.     or    ax,ax            ; offset 0?
  1960.     jnz    freepok
  1961.     add    dx,1000h        ; adjust segment
  1962. freepok:
  1963.     ENDIF
  1964.     mov    cl,4
  1965.     shr    ax,cl
  1966.     add    ax,dx        ;e FreeList/HeapEnd segment (rounded down)
  1967.                 ;d Segment von Freiliste/HeapEnd (abgerundet)
  1968.     dec    ax        ; MCB addr FreeList/HeapEnd segment
  1969.     mov    si,ax
  1970. ;
  1971.     mov    bx,word ptr HeapPtr
  1972.     mov    dx,word ptr HeapPtr+2
  1973.     add    bx,0fh
  1974.     shr    bx,cl
  1975.     add    bx,dx        ; heap end segment (rounded up)
  1976.     mov    di,bx
  1977. ;
  1978.     sub    ax,bx        ; free heap size
  1979.     jc    pnofree
  1980.     cmp    ax,1024        ;e don't bother if less than 16k
  1981.                 ;d nicht freigeben wenn weniger als 16k
  1982.     jbe    pnofree
  1983. ;
  1984.     mov    ax,PrefixSeg    ; PSP
  1985.     sub    bx,ax        ; size of space in use
  1986.     dec    ax        ; MCB
  1987.     mov    es,ax
  1988.     inc    ax
  1989. ;
  1990. ;e    Modify base MCB to contain only the part up to HeapPtr.
  1991. ;d    Den Basis-MCB modifizieren, daß er nur den Teil bis HeapPtr enthält.
  1992. ;
  1993.     mov    cl,es:id    ; save MCB ID
  1994.     mov    swap_prep.pmemid,cl
  1995.     mov    es:id,'M'
  1996.     mov    dx,es:paras
  1997.     mov    swap_prep.pmempar,dx
  1998.     mov    es:paras,bx
  1999. ;
  2000. ;e    Insert new, free, MCB at address HeapPtr.
  2001. ;d    Neuen, als frei markierten, MCB an Adresse HeapPtr einfügen.
  2002. ;
  2003.     mov    es,di        ; HeapPtr
  2004.     sub    dx,bx
  2005.     dec    dx
  2006.     mov    es:id,'M'
  2007.     mov    es:owner,0
  2008.     mov    bx,si        ; HeapEnd/FreeList
  2009.     sub    bx,di        ; - HeapPtr
  2010.     dec    bx        ; - 1 (MCB)
  2011.     mov    es:paras,bx
  2012. ;
  2013.     sub    dx,bx
  2014.     dec    dx
  2015.     jnz    frnotempty
  2016.     inc    es:paras
  2017.     mov    es:id,cl
  2018.     jmp    short pnofree
  2019. ;>e
  2020. ;    There is a non-empty block after HeapEnd/FreePtr. Insert an MCB
  2021. ;    with Owner = PSP.
  2022. ;<
  2023. ;>d
  2024. ;    Es existiert ein nicht leerer Block nach HeapEnd/FreePtr. Einen
  2025. ;    MCB mit Owner = PSP erzeugen.
  2026. ;<
  2027. frnotempty:
  2028.     mov    es,si        ; HeapEnd/FreeList
  2029.     mov    es:id,cl
  2030.     mov    es:owner,ax
  2031.     mov    es:paras,dx
  2032. ;
  2033. pnofree:
  2034.     ret
  2035. ;
  2036. @freepas    endp
  2037. ;>e
  2038. ;    @restpas - restore original memory layout modified by @freepas
  2039. ;<    
  2040. ;>d
  2041. ;    @restpas - von @freepas modifiziertes Original-Speicher-Layout 
  2042. ;           wiederherstellen
  2043. ;<    
  2044. @restpas    proc    near
  2045. ;
  2046.     mov    al,swap_prep.pmemid
  2047.     or    al,al
  2048.     jz    norestpas
  2049.     mov    bx,PrefixSeg
  2050.     dec    bx
  2051.     mov    es,bx
  2052.     mov    es:id,al
  2053.     mov    ax,swap_prep.pmempar
  2054.     mov    es:paras,ax
  2055. ;
  2056. norestpas:
  2057.     ret
  2058. ;
  2059. @restpas    endp
  2060.     ENDIF
  2061.     ENDIF
  2062. ;
  2063. ;--------------------------------------------------------------------------
  2064. ;--------------------------------------------------------------------------
  2065. ;
  2066. ;
  2067.     IFDEF    PASCAL
  2068.     IFDEF    FARCALL
  2069. do_spawn    PROC    far swapping: word, execfname: dword, params: dword, envlen: word, envp: dword, stdin: dword, stdout: dword, stderr: dword
  2070.     ELSE
  2071. do_spawn    PROC    near swapping: word, execfname: dword, params: dword, envlen: word, envp: dword, stdin: dword, stdout: dword, stderr: dword
  2072.     ENDIF
  2073.     ELSE
  2074. do_spawn    PROC    uses si di,swapping: word, execfname:ptr byte,params:ptr byte,envlen:word,envp:ptr byte,stdin:ptr byte, stdout:ptr byte, stderr:ptr byte
  2075.     ENDIF
  2076.     local    datseg,pspseg,currmcb,dos33
  2077. ;
  2078.     IFDEF    TC_HUGE
  2079.     mov    ax,SEG my_data
  2080.     mov    ds,ax
  2081.     ENDIF
  2082. ;
  2083.     mov    datseg,ds        ;e save default DS
  2084.                     ;d Default-DS sichern
  2085. ;
  2086.     mov    dos33,0
  2087.     mov    ax,3000h        ; get DOS version
  2088.     int    21h
  2089.     cmp    al,3
  2090.     jb    notdos33
  2091.     ja    isdos33
  2092.     cmp    ah,33
  2093.     jb    notdos33
  2094. isdos33:
  2095.     mov    dos33,1
  2096. notdos33:
  2097. ;
  2098.     IFDEF    PASCAL
  2099.     cld
  2100.     mov    bx,prefixseg
  2101.     ELSE
  2102.     IFDEF    TC_HUGE
  2103.     mov    ax,SEG _psp
  2104.     mov    es,ax
  2105.     mov    bx,es:_psp
  2106.     ELSE
  2107.     mov    bx,_psp
  2108.     ENDIF
  2109.     ENDIF
  2110.     mov    pspseg,bx
  2111. ;
  2112. ;e    Check if spawn is too low in memory
  2113. ;d    Prüfen ob dieses Modul zu weit unten im Speicher liegt
  2114. ;
  2115.     mov    ax,cs
  2116.     mov    dx,offset lowcode_begin
  2117.     mov    cl,4
  2118.     shr    dx,cl
  2119.     add    ax,dx            ;e normalized start of this code
  2120.                     ;d Normalisierter Beginn des Codes
  2121.     mov    dx,keep_paras        ;e the end of the modified area
  2122.                     ;d Ende des modifizierten Bereichs
  2123.     add    dx,bx            ;e plus PSP = end paragraph
  2124.                     ;d plus PSP = letzer Paragraph
  2125.     cmp    ax,dx
  2126.     ja    doswap_ok    ;e ok if start of code > end of low mem
  2127.                 ;d OK wenn Code-Beginn > Ende residenter Teil
  2128.     mov    ax,RC_TOOLOW
  2129.     ret
  2130. ;
  2131. doswap_ok:
  2132.     cmp    swapping,0
  2133.     jle    method_ok
  2134. ;
  2135. ;e    check the swap method, to make sure prep_swap has been called
  2136. ;d    Prüfen Auslagerungsmethode um sicherzustellen daß prep_swap
  2137. ;d    aufgerufen wurde.
  2138. ;
  2139.     mov    al,swap_prep.swapmethod
  2140.     cmp    al,USE_EMS
  2141.     je    method_ok
  2142.     cmp    al,USE_XMS
  2143.     je    method_ok
  2144.     cmp    al,USE_FILE
  2145.     je    method_ok
  2146.     mov    ax,RC_BADPREP
  2147.     ret
  2148. ;>e
  2149. ;    Save the memory below the swap space.
  2150. ;    We must do this before swapping, so the saved memory is
  2151. ;    in the swapped out image.
  2152. ;    Anything else we'd want to save on the stack or anywhere
  2153. ;    else in "normal" memory also has to be saved here, any
  2154. ;    modifications done to memory after the swap will be lost.
  2155. ;
  2156. ;    Note that the memory save is done even when not swapping,
  2157. ;    because we use some of the variables in low core for
  2158. ;    simplicity.
  2159. ;<
  2160. ;>d
  2161. ;    Sichern des Speichers unterhalb des Auslagerungsbereichs.
  2162. ;    Dies muß vor dem Auslagern geschehen damit der gesicherte
  2163. ;    Bereich mit im Ausgelagerten Abbild ist.
  2164. ;    Auch alles Andere das auf dem Stack oder sonst im "normalen"
  2165. ;    Speicher gesichert werden soll muß hier gesichert werden,
  2166. ;    da alle Modifikationen des Speichers die nach dem Auslagern
  2167. ;    erfolgen verloren gehen.
  2168. ;
  2169. ;    Das Sichern des Speichers ist auch notwendig wenn keine Auslagerung
  2170. ;    stattfindet, da Teile des sonst residenten Bereichs im unteren
  2171. ;    Speicher in jedem Fall verwendet werden.
  2172. ;<
  2173. method_ok:
  2174.     mov    es,datseg
  2175.     mov    ds,pspseg        ;e DS points to PSP
  2176.                     ;d DS zeigt auf PSP
  2177.     mov    si,5ch
  2178.     mov    di,offset save_dat
  2179.     mov    cx,savespace / 2    ;e NOTE: savespace is always even
  2180.                     ;d HINWEIS: savespace ist stets gerade
  2181.     rep movsw
  2182. ;
  2183.     mov    ds,datseg
  2184.     IFDEF    PASCAL
  2185.     IF    PAS_FREE
  2186.     call    @freepas
  2187.     ENDIF
  2188.     ENDIF
  2189. ;
  2190.     mov    ax,swapping
  2191.     cmp    ax,0
  2192.     jg    begin_swap
  2193. ;>e
  2194. ;    not swapping, prep_swap wasn't called. Init those variables in
  2195. ;      the 'swap_prep' block we need in any case.
  2196. ;<
  2197. ;>d
  2198. ;    Keine Auslagerung, prep_swap wurde nicht aufgerufen. Die Variablen
  2199. ;    im 'swap_prep'-Block initialisieren die in jedem Fall gebraucht werden.
  2200. ;<
  2201.     mov    swap_prep.swapmethod,al
  2202.     je    no_reduce
  2203. ;
  2204.     mov    ax,pspseg
  2205.     dec    ax
  2206.     mov    swap_prep.psp_mcb,ax
  2207.     mov    swap_prep.first_mcb,ax
  2208.     inc    ax
  2209.     mov    es,ax
  2210.     mov    bx,es:psp_envptr
  2211.     mov    swap_prep.env_mcb,bx
  2212.     mov    swap_prep.noswap_mcb,0
  2213.     cmp    envlen,0
  2214.     jne    swp_can_swap_env
  2215.     mov    swap_prep.noswap_mcb,bx
  2216. ;
  2217. swp_can_swap_env:
  2218.     IF    NOT NO_INHERIT
  2219.     mov    swap_prep.noswap_mcb2,0
  2220.     cmp    dos33,0
  2221.     je    swp_no_exthandle
  2222.     mov    ax,es:psp_handleptrs
  2223.     mov    bx,es
  2224.     cmp    ax,bx
  2225.     je    swp_no_exthandle
  2226.     dec    ax
  2227.     mov    swap_prep.noswap_mcb2,ax
  2228. ;
  2229. swp_no_exthandle:
  2230.     ENDIF
  2231.     xor    bx,bx
  2232.     mov    es,bx
  2233.     mov    ah,52h            ; get list of lists
  2234.     int    21h
  2235.     mov    ax,es
  2236.     or    ax,bx
  2237.     jz    no_reduce
  2238.     mov    es,es:[bx-2]        ; first MCB
  2239.     cmp    es:id,4dh        ; normal ID?
  2240.     jne    no_reduce
  2241.     mov    swap_prep.first_mcb,es
  2242. ;
  2243. no_reduce:
  2244.     jmp    no_swap1
  2245. ;
  2246. ;e    set up first block descriptor
  2247. ;d    Ersten Block-Deskriptor aufsetzen
  2248. ;
  2249. begin_swap:
  2250.     mov    ax,swap_prep.first_mcb
  2251.     mov    currmcb,ax
  2252.     mov    es,swap_prep.psp_mcb    ;e let ES point to base MCB
  2253.                     ;d ES zeigt auf Basis-MCB
  2254.     mov    ax,es:paras
  2255.     mov    currdesc.msize,ax
  2256.     sub    ax,keep_paras
  2257.     mov    currdesc.swsize,ax
  2258.     mov    currdesc.addr,es
  2259.     mov    currdesc.swoffset,swapbeg + 16
  2260. ;e        NOTE: swapbeg is 1 para higher when seen from MCB
  2261. ;d        HINWEIS: swapbeg ist 1 Paragraph höher vom MCB aus gesehen
  2262.     mov    ax,swap_prep.total_mcbs
  2263.     mov    currdesc.num_follow,ax
  2264. ;
  2265. ;e    init other vars
  2266. ;d    andere Variablen initialisieren
  2267. ;
  2268.     mov    xmsctl.destlo,0
  2269.     mov    xmsctl.desthi,0
  2270.     mov    ems_curpage,0
  2271.     mov    ems_curoff,ems_parasize
  2272. ;>e
  2273. ;    Do the swapping. Each MCB block (except the last) has an 
  2274. ;    "mcbdesc" structure appended that gives location and size 
  2275. ;    of the next MCB.
  2276. ;<
  2277. ;>d
  2278. ;    Auslagerung ausführen. An jeden MCB-Block (außer den letzten)
  2279. ;    wird eine "mcbdesc" Struktur zur Beschreibung von Adresse und
  2280. ;    Größe des nächsten Blocks angefügt.
  2281. ;<
  2282. swapout_main:
  2283.     cmp    currdesc.num_follow,0    ;e next block?
  2284.                     ;d Gibt es einen nächsten?
  2285.     je    swapout_no_next        ;e ok if not
  2286.                     ;d OK wenn nein
  2287. ;>e
  2288. ;    There is another MCB block to be saved. So we don't have
  2289. ;    to do two calls to the save routine with complicated
  2290. ;    parameters, we set up the next MCB descriptor beforehand.
  2291. ;    Walk the MCB chain starting at the current MCB to find
  2292. ;    the next one belonging to this process.
  2293. ;<
  2294. ;>d
  2295. ;    Es gibt einen weiteren auszulagernden MCB-Block. Um die 
  2296. ;    Auslagerungsroutine nicht getrennt für den MCB-Deskriptor
  2297. ;    aufrufen zu müssen (mit einer entsprechend aufwendigeren
  2298. ;    Parameterversorgung), wird der Deskriptor für den Folgeblock
  2299. ;    vor Aufruf erstellt.
  2300. ;    Dazu muß die MCB-Kette, beginnend beim derzeitigen Block,
  2301. ;    durchgegangen werden um den nächsten zum Prozeß gehörenden
  2302. ;    Block zu finden.
  2303. ;<
  2304.     mov    ax,currmcb
  2305.     mov    bx,pspseg
  2306.     mov    cx,swap_prep.psp_mcb
  2307.     mov    dx,swap_prep.noswap_mcb
  2308. ;
  2309. swm_mcb_walk:
  2310.     mov    es,ax
  2311.     cmp    ax,cx
  2312.     je    swm_next_mcb
  2313.     cmp    ax,dx
  2314.     je    swm_next_mcb
  2315.     IF    NOT NO_INHERIT
  2316.     cmp    ax,swap_prep.noswap_mcb2
  2317.     je    swm_next_mcb
  2318.     ENDIF
  2319. ;
  2320.     cmp    bx,es:owner        ;e our process?
  2321.                     ;d Dieser Prozeß?
  2322.     je    swm_mcb_found        ;e found it if yes
  2323.                     ;d gefunden wenn ja
  2324. ;
  2325. swm_next_mcb:
  2326.     cmp    es:id,4dh        ;e normal block?
  2327.                     ;d Normaler Block?
  2328.     jne    swm_mcb_error        ;e error if end of chain
  2329.                     ;d Fehler wenn Ende der Kette
  2330.     add    ax,es:paras        ; start + length
  2331.     inc    ax            ; next MCB
  2332.     jmp    swm_mcb_walk
  2333. ;
  2334. ;e    MCB found, set up an mcbdesc in the "nextmcb" structure
  2335. ;d    MCB gefunden, aufsetzen mcbdesc in der "nextmcb" Struktur
  2336. ;
  2337. swm_mcb_found:
  2338.     mov    nextmcb.addr,es
  2339.     mov    ax,es:paras        ;e get number of paragraphs
  2340.                     ;d Anzahl Paragraphen
  2341.     mov    nextmcb.msize,ax    ;e and save
  2342.                     ;d sichern
  2343.     inc    ax
  2344.     mov    nextmcb.swsize,ax
  2345.     mov    bx,es
  2346.     add    bx,ax
  2347.     mov    currmcb,bx
  2348.     mov    nextmcb.swoffset,0
  2349.     mov    ax,currdesc.num_follow
  2350.     dec    ax
  2351.     mov    nextmcb.num_follow,ax
  2352. ;
  2353. swapout_no_next:
  2354.     cmp    swap_prep.swapmethod,USE_EMS
  2355.     je    swm_ems
  2356.     cmp    swap_prep.swapmethod,USE_XMS
  2357.     je    swm_xms
  2358.     call    swapout_file
  2359.     jmp    short swm_next
  2360. ;
  2361. swm_ems:
  2362.     call    swapout_ems
  2363.     jmp    short swm_next
  2364. ;
  2365. swm_xms:
  2366.     call    swapout_xms
  2367. ;
  2368. swm_next:
  2369.     jnz    swapout_error
  2370.     cmp    currdesc.num_follow,0
  2371.     je    swapout_complete
  2372. ;>e
  2373. ;    next MCB exists, copy the "nextmcb" descriptor into
  2374. ;    currdesc, and loop.
  2375. ;<
  2376. ;>d
  2377. ;    Es gibt einen Folgeblock, der "nextmcb" Deskriptor wird in den
  2378. ;    "currdesc" Deskriptor kopiert, und das ganze noch mal von vorn.
  2379. ;<
  2380.     mov    es,datseg
  2381.     mov    si,offset nextmcb
  2382.     mov    di,offset currdesc
  2383.     mov    cx,TYPE mcbdesc
  2384.     rep movsb
  2385.     jmp    swapout_main
  2386. ;
  2387. ;
  2388. swm_mcb_error:
  2389.     mov    ax,RC_MCBERROR
  2390. ;
  2391. swapout_kill:
  2392.     cmp    swapping,0
  2393.     jl    swapout_error
  2394.     push    ax
  2395.     cmp    swap_prep.swapmethod,USE_FILE
  2396.     je    swm_mcberr_file
  2397.     cmp    swap_prep.swapmethod,USE_EMS
  2398.     je    swm_mcberr_ems
  2399. ;
  2400.     mov    ah,0ah            ;e release XMS frame on error
  2401.                     ;d Bei Fehler XMS-Block freigeben
  2402.     mov    dx,swap_prep.handle    ; XMS handle
  2403.     call    swap_prep.xmm
  2404.     pop    ax
  2405.     jmp    short swapout_error
  2406. ;
  2407. swm_mcberr_ems:
  2408.     mov    dx,swap_prep.handle    ; EMS handle
  2409.     mov    ah,45h            ;e release EMS pages on error
  2410.                     ;d Bei Fehler EMS freigeben
  2411.     int    EMM_INT
  2412.     pop    ax
  2413.     jmp    short swapout_error
  2414. ;
  2415. swm_mcberr_file:
  2416.     mov    bx,swap_prep.handle
  2417.     cmp    bx,-1
  2418.     je    swm_noclose
  2419.     mov    ah,3eh            ; close file
  2420.     int    21h
  2421. swm_noclose:
  2422.     mov    dx,offset swap_prep.swapfilename
  2423.     mov    ah,41h            ; delete file
  2424.     int    21h
  2425.     pop    ax
  2426. ;
  2427. swapout_error:
  2428.     IFDEF    PASCAL
  2429.     IF    PAS_FREE
  2430.     call    @restpas
  2431.     ENDIF
  2432.     ENDIF
  2433.     ret
  2434. ;
  2435. ;>e
  2436. ;    Swapout complete. Close the handle (EMS/file only),
  2437. ;    then set up low memory.
  2438. ;<
  2439. ;>d
  2440. ;    Auslagerung abgeschlossen. Die Datei bzw. die EMS-Seite wird
  2441. ;    geschlossen, und der residente Bereich wird initialisiert.
  2442. ;<
  2443. swapout_complete:
  2444.     cmp    swap_prep.swapmethod,USE_FILE
  2445.     jne    swoc_nofile
  2446. ;
  2447. ;e    File swap: Close the swap file to make the handle available
  2448. ;d    Auslagerung auf Datei: Datei schließen um den Handle freizumachen
  2449. ;
  2450.     mov    bx,swap_prep.handle
  2451.     mov    swap_prep.handle,-1
  2452.     mov    ah,3eh
  2453.     int    21h            ; close file
  2454.     mov    si,offset swapin_file
  2455.     jnc    swoc_ready
  2456.     mov    ax,RC_SWAPERROR
  2457.     jmp    swapout_kill
  2458. ;
  2459. swoc_nofile:
  2460.     cmp    swap_prep.swapmethod,USE_EMS
  2461.     jne    swoc_xms
  2462. ;
  2463. ;e    EMS: Unmap page
  2464. ;d    EMS: Seite unzugänglich machen
  2465. ;
  2466.     mov    ax,4400h
  2467.     mov    bx,-1
  2468.     mov    dx,swap_prep.handle
  2469.     int    EMM_INT
  2470.     mov    si,offset swapin_ems
  2471.     jmp    short swoc_ready
  2472. ;
  2473. swoc_xms:
  2474.     mov    si,offset swapin_xms
  2475.     jmp    short swoc_ready
  2476. ;
  2477. no_swap1:
  2478.     mov    si,offset swapin_none
  2479. ;    
  2480. ;e    Copy the appropriate swap-in routine to low memory.
  2481. ;d    Kopieren der der Auslagerungsmethode entsprechenden Routine
  2482. ;d    in den residenten Teil.
  2483. ;
  2484. swoc_ready:
  2485.     mov    es,pspseg
  2486.     mov    cx,swap_codelen / 2
  2487.     mov    di,codebeg + base_length
  2488.     push    ds
  2489.     mov    ax,cs
  2490.     mov    ds,ax
  2491.     rep movsw
  2492. ;>e
  2493. ;    And while we're at it, copy the MCB allocation routine (which
  2494. ;    also includes the initial MCB release and exec call) down.
  2495. ;<
  2496. ;>d
  2497. ;    Außerdem die MCB-Allozierungsroutine und den EXEC-Aufruf
  2498. ;    nach unten kopieren.
  2499. ;<
  2500.     mov    cx,base_length / 2
  2501.     mov    di,param_len
  2502.     mov    si,offset lowcode_begin
  2503.     rep movsw
  2504. ;
  2505.     pop    ds
  2506.     mov    bx,es
  2507.     dec    bx
  2508.     mov    es,bx        ;e let ES point to base MCB
  2509.                 ;d ES zeigt jetzt auf den Basisblock
  2510. ;>e
  2511. ;    Again set up the base MCB descriptor, and copy it as well as
  2512. ;    the variables set up by prep_swap to low memory.
  2513. ;    This isn't too useful if we're not swapping, but it doesn't
  2514. ;    hurt, either. The only variable used when not swapping is
  2515. ;    lprep.swapmethod.
  2516. ;<
  2517. ;>d
  2518. ;    Der Deskriptor für den Basisblock wird erneut aufgesetzt und,
  2519. ;    zusammen mit dem Variablenblock der durch prep_swap initialisiert
  2520. ;    wurde, nach unten kopieren.
  2521. ;    Wenn gar nicht ausgelagert wird, ist dies eigentlich nicht nicht
  2522. ;    notwendig, es schadet aber auch nicht. Die einzige Variable
  2523. ;    die in diesem Fall benötigt wird ist lprep.swapmethod.
  2524. ;<
  2525.     mov    ax,es:paras
  2526.     mov    currdesc.msize,ax
  2527.     sub    ax,keep_paras
  2528.     mov    currdesc.swsize,ax
  2529.     mov    currdesc.addr,es
  2530.     mov    currdesc.swoffset,swapbeg + 16
  2531.     mov    ax,swap_prep.total_mcbs
  2532.     mov    currdesc.num_follow,ax
  2533. ;
  2534.     mov    es,pspseg        ;e ES points to PSP again
  2535.                     ;d ES zeigt wieder auf PSP
  2536. ;
  2537.     mov    cx,TYPE prep_block
  2538.     mov    si,offset swap_prep
  2539.     mov    di,lprep
  2540.     rep movsb
  2541.     mov    cx,TYPE mcbdesc
  2542.     mov    si,offset currdesc
  2543.     mov    di,lcurrdesc
  2544.     rep movsb
  2545. ;
  2546. ;e    now set up other variables in low core
  2547. ;d    Nun werden die weiteren Variablen im residenten Tail initialisiert.
  2548. ;
  2549.     mov    ds,pspseg
  2550.     mov    ds:cgetmcb,getmcboff + codebeg
  2551.     mov    ds:eretcode,0
  2552.     mov    ds:retflags,0
  2553. ;
  2554. ;>e
  2555. ;    If 'NO_INHERIT' is nonzero, save the entries of the 
  2556. ;    handle table, and set the last 15 to 0ffh (unused).
  2557. ;<
  2558. ;>d
  2559. ;    Wenn 'NO_INHERIT' nicht 0 ist, Retten der Handle-Tabelle
  2560. ;    und Setzen der letzten 15 Einträge auf 0ffh (unbenutzt).
  2561. ;<
  2562.     IF    NO_INHERIT
  2563.     mov    si,psp_handletab
  2564.     mov    di,lhandlesave
  2565.     mov    cx,10
  2566.     rep movsw
  2567.     mov    si,psp_handlenum    ;e Length of handle table
  2568.                     ;d Länge Handle-Tabelle
  2569.     mov    ax,[si]
  2570.     stosw
  2571.     mov    word ptr [si],20    ;e set to default to be safe
  2572.                     ;d Auf Standardwert setzten
  2573.     add    si,2
  2574.     lodsw                ;e Handle table pointer
  2575.                     ;d Zeiger auf Handle-Tabelle
  2576.     mov    bx,ax
  2577.     stosw
  2578.     lodsw
  2579.     stosw
  2580.     cmp    dos33,0
  2581.     je    no_handlecopy
  2582.     cmp    ax,pspseg
  2583.     jne    copy_handles
  2584.     cmp    bx,psp_handletab
  2585.     je    no_handlecopy
  2586. ;>e
  2587. ;    if the handle table pointer in the PSP does not point to
  2588. ;    the default PSP location, copy the first five entries from
  2589. ;    this table into the PSP - but only if we have DOS >= 3.3.
  2590. ;<
  2591. ;>d
  2592. ;    Wenn der Handle-Tabellen-Pointer im PSP nicht auf den
  2593. ;    Standard-Platz im PSP zeigt, die ersten fünf Einträge
  2594. ;    aus dieser Tabelle in den PSP kopieren - aber nur bei
  2595. ;    einer DOS-Version >= 3.3.
  2596. ;<
  2597. copy_handles:
  2598.     mov    ds,ax
  2599.     mov    si,bx
  2600.     mov    di,psp_handletab
  2601.     mov    es:psp_handleptro,di
  2602.     mov    es:psp_handleptrs,es
  2603.     movsw
  2604.     movsw
  2605.     movsb
  2606. ;
  2607. no_handlecopy:
  2608.     mov    di,psp_handletab+5
  2609.     mov    ax,0ffffh
  2610.     stosb
  2611.     mov    cx,7
  2612.     rep stosw
  2613. ;
  2614.     ENDIF
  2615. ;
  2616. ;e    Handle Redirection
  2617. ;d    Dateiumleitung behandeln
  2618. ;
  2619.     IF    REDIRECT
  2620.     mov    es,pspseg
  2621.     mov    di,lstdinsav
  2622.     mov    ax,-1
  2623.     stosw
  2624.     stosw
  2625.     stosw
  2626.     mov    di,lstdinsav
  2627.     xor    cx,cx
  2628.     IF    ptrsize
  2629.     lds    si,stdin
  2630.     mov    ax,ds
  2631.     or    ax,si
  2632.     ELSE
  2633.     mov    si,stdin
  2634.     mov    ds,datseg
  2635.     or    si,si
  2636.     ENDIF
  2637.     call    @redirect
  2638.     jc    failed_redir
  2639.     inc    cx
  2640.     IF    ptrsize
  2641.     lds    si,stdout
  2642.     mov    ax,ds
  2643.     or    ax,si
  2644.     ELSE
  2645.     mov    si,stdout
  2646.     or    si,si
  2647.     ENDIF
  2648.     call    @redirect
  2649.     jc    failed_redir
  2650.     inc    cx
  2651.     IF    ptrsize
  2652.     lds    si,stderr
  2653.     mov    ax,ds
  2654.     or    ax,si
  2655.     ELSE
  2656.     mov    si,stderr
  2657.     or    si,si
  2658.     ENDIF
  2659.     call    @redirect
  2660.     jnc    redir_complete
  2661. ;
  2662. failed_redir:
  2663.     push    ax
  2664. ;
  2665. ;e    restore handle table and pointer
  2666. ;d    Wiederherstellen Handle-Tabelle und Pointer
  2667. ;
  2668.     mov    ds,pspseg
  2669.     mov    si,lstdinsav
  2670.     xor    cx,cx
  2671. ;
  2672. redirclose:
  2673.     lodsw
  2674.     cmp    ax,-1
  2675.     je    redclosenext
  2676.     mov    bx,ax
  2677.     mov    ah,46h
  2678.     int    21h
  2679. ;
  2680. redclosenext:
  2681.     inc    cx
  2682.     cmp    cx,3
  2683.     jb    redirclose
  2684. ;
  2685.     IF    NO_INHERIT
  2686.     mov    ds,pspseg
  2687.     mov    es,pspseg
  2688.     mov    si,lhandlesave
  2689.     mov    di,psp_handletab
  2690.     mov    cx,10
  2691.     rep movsw
  2692.     mov    di,psp_handlenum
  2693.     movsw
  2694.     movsw
  2695.     movsw
  2696.     ENDIF
  2697. ;
  2698. ;e    Restore overwritten part of program
  2699. ;d    Den überschriebenen Teil des Programms wiederherstellen
  2700. ;
  2701.     mov    ds,datseg
  2702.     mov    es,pspseg
  2703.     mov    si,offset save_dat
  2704.     mov    di,5ch
  2705.     mov    cx,savespace
  2706.     rep movsb
  2707. ;
  2708.     pop    ax
  2709.     mov    ah,RC_REDIRFAIL SHR 8
  2710.     jmp    swapout_kill
  2711. ;
  2712. redir_complete:
  2713.     IF    NO_INHERIT
  2714.     mov    ds,pspseg
  2715.     mov    es,pspseg
  2716.     mov    si,psp_handletab+5
  2717.     mov    di,lredirsav
  2718.     mov    cx,3
  2719.     rep movsw
  2720.     mov    di,psp_handletab+5
  2721.     mov    cx,3
  2722.     mov    ax,0ffffh
  2723.     rep stosw
  2724.     ENDIF
  2725.     ENDIF
  2726. ;
  2727. ;e    Prepare exec parameter block
  2728. ;d    Parameterblock für EXEC-Aufruf vorbereiten
  2729. ;
  2730.     mov    ax,es
  2731.     mov    es:expar.fcb1seg,ax
  2732.     mov    es:expar.fcb2seg,ax
  2733.     mov    es:expar.pparseg,ax
  2734.     mov    es:expar.envseg,0
  2735. ;>e
  2736. ;    The 'zero' word is located at 80h in the PSP, the start of
  2737. ;    the command line. So as not to confuse MCB walking programs,
  2738. ;    a command line length of zero is inserted here.
  2739. ;<
  2740. ;>d
  2741. ;    Das 'zero'-Wort ist an Adresse 80h im PSP, dem Beginn der
  2742. ;    Kommandozeile. Um Programme die die MCB-Kette abarbeiten
  2743. ;    und dabei möglicherweise auf diese Kommandozeile zugreifen
  2744. ;    nicht zu verwirren, wird eine leere Kommandozeile eingefügt.
  2745. ;<
  2746.     mov    es:zero,0d00h        ;e 00h,0dh = empty command line
  2747.                     ;d 00h,0dh = Leere Kommandozeile
  2748. ;
  2749. ;e    Init default fcb's by parsing parameter string
  2750. ;d    Default FCB-Blöcke aus dem Parameter-String füllen
  2751. ;
  2752.     IF    ptrsize
  2753.     lds    si,params
  2754.     ELSE
  2755.     mov    si,params
  2756.     mov    ds,datseg
  2757.     ENDIF
  2758.     IFDEF    PASCAL
  2759.     inc    si            ;e skip length byte
  2760.                     ;d Längenbyte überspringen
  2761.     ENDIF
  2762.     push    si
  2763.     mov    di,xfcb1
  2764.     mov    es:expar.fcb1,di
  2765.     push    di
  2766.     mov    cx,16
  2767.     xor    ax,ax
  2768.     rep stosw            ;e init both fcb's to 0
  2769.                     ;d Beide FCBs mit 0 vorbesetzen
  2770.     pop    di
  2771.     mov    ax,2901h
  2772.     int    21h
  2773.     mov    di,xfcb2
  2774.     mov    es:expar.fcb2,di
  2775.     mov    ax,2901h
  2776.     int    21h
  2777.     pop    si
  2778. ;
  2779. ;e    move command tail string into low core
  2780. ;d    Kommandozeile in residenten Teil transferieren
  2781. ;
  2782.     mov    di,progpars
  2783.     mov    es:expar.ppar,di
  2784.     xor    cx,cx
  2785.     inc    di
  2786. cmdcpy:
  2787.     lodsb
  2788.     or    al,al
  2789.     jz    cmdcpy_end
  2790.     stosb
  2791.     inc    cx
  2792.     jmp    cmdcpy
  2793. ;
  2794. cmdcpy_end:
  2795.     mov    al,0dh
  2796.     stosb
  2797.     mov    es:progpars,cl
  2798. ;
  2799. ;e    move filename string into low core
  2800. ;d    Dateinamen in residenten Teil transferieren
  2801. ;
  2802.     IF    ptrsize
  2803.     lds    si,execfname
  2804.     ELSE
  2805.     mov    si,execfname
  2806.     ENDIF
  2807.     IFDEF    PASCAL
  2808.     inc    si
  2809.     ENDIF
  2810.     mov    di,filename
  2811. fncpy:
  2812.     lodsb
  2813.     stosb
  2814.     or    al,al
  2815.     jnz    fncpy
  2816. ;
  2817. ;e    Setup environment copy
  2818. ;d    Umgebungsvariablenblock-Kopie aufsetzen
  2819. ;
  2820.     mov    bx,keep_paras        ;e paras to keep
  2821.                     ;d Residente Paragraphen
  2822.     mov    cx,envlen        ;e environment size
  2823.                     ;d Größe Umgebungsvariablen
  2824.     jcxz    no_environ        ;e go jump if no environment
  2825.                     ;d Fertig wenn keine Umgebung
  2826.     cmp    swapping,0
  2827.     jne    do_envcopy
  2828. ;>e
  2829. ;    Not swapping, use the environment pointer directly.
  2830. ;    Note that the environment copy must be paragraph aligned.
  2831. ;<
  2832. ;>d
  2833. ;    Keine Auslagerung, der Umgebungs-Zeiger kann direkt verwendet
  2834. ;    werden. Dazu muß die Kopie der Umgebungsvariablen auf Paragraphen-
  2835. ;    Grenze adjustiert sein.
  2836. ;<
  2837.     IF    ptrsize
  2838.     mov    ax,word ptr (envp)+2
  2839.     mov    bx,word ptr (envp)
  2840.     ELSE
  2841.     mov    ax,ds
  2842.     mov    bx,envp
  2843.     ENDIF
  2844.     add    bx,15            ;e make sure it's paragraph aligned
  2845.                     ;d auf Paragraphengrenze bringen
  2846.     mov    cl,4
  2847.     shr    bx,cl            ;e and convert to segment addr
  2848.                     ;d in Segment-Adresse konvertieren
  2849.     add    ax,bx
  2850.     mov    es:expar.envseg,ax    ;e new environment segment
  2851.                     ;d Neues Umgebungs-Segment
  2852.     xor    cx,cx            ;e mark no copy
  2853.                     ;d Markieren daß keine Kopie nötig
  2854.     xor    bx,bx            ;e and no shrink
  2855.                     ;d und keine Speicherreduzierung
  2856.     jmp    short no_environ
  2857. ;>e
  2858. ;    Swapping or EXECing without return. Set up the pointers for
  2859. ;    an environment copy (we can't do the copy yet, it might overwrite
  2860. ;    this code).
  2861. ;<
  2862. ;>d
  2863. ;    Auslagerung, oder EXEC ohne Rückkehr. Die Zeiger für das
  2864. ;    kopieren der Umgebungsvariablen aufsetzen. Der Block darf
  2865. ;    jetzt noch nicht kopiert werden, da dies eventuell den gerade
  2866. ;    ausgeführten Code überschreiben könnte.
  2867. ;<
  2868. do_envcopy:
  2869.     inc    cx
  2870.     shr    cx,1            ;e words to copy
  2871.                     ;d Zu kopierende Worte
  2872.     mov    ax,cx            ;e convert envsize to paras
  2873.                     ;d in Paragraphen konvertieren
  2874.     add    ax,7
  2875.     shr    ax,1
  2876.     shr    ax,1
  2877.     shr    ax,1
  2878.     add    bx,ax            ;e add envsize to paras to keep
  2879.                     ;d Größe zu residenter addieren
  2880.     IF    ptrsize
  2881.     lds    si,envp
  2882.     ELSE
  2883.     mov    si,envp
  2884.     ENDIF
  2885. ;
  2886.     mov    ax,es            ;e low core segment
  2887.                     ;d Segmentadresse residenter Teil
  2888.     add    ax,keep_paras        ;e plus fixed paras
  2889.                     ;d plus residente Paragraphen
  2890.     mov    es:expar.envseg,ax    ;e = new environment segment
  2891.                     ;d = neues Umgebungs-Segment
  2892. ;
  2893. ;e    Save stack regs, switch to local stack
  2894. ;d    Sichern Stack-Register, Umschalten auf lokalen Stack
  2895. ;
  2896. no_environ:
  2897.     mov    es:save_ss,ss
  2898.     mov    es:save_sp,sp
  2899.     mov    ax,es
  2900.     cli
  2901.     mov    ss,ax
  2902.     mov    sp,mystack
  2903.     sti
  2904. ;
  2905.     push    cx            ; save env length
  2906.     push    si            ; save env pointer
  2907.     push    ds            ; save env segment
  2908. ;
  2909. ;e    save and patch INT0 (division by zero) vector
  2910. ;d    Sichern und überschreiben INT0 (division by zero) Vektor
  2911. ;
  2912.     xor    ax,ax
  2913.     mov    ds,ax
  2914.     mov    ax,word ptr ds:0
  2915.     mov    es:div0_off,ax
  2916.     mov    ax,word ptr ds:2
  2917.     mov    es:div0_seg,ax
  2918.     mov    word ptr ds:0,codebeg + iretoff
  2919.     mov    word ptr ds:2,es
  2920. ;
  2921.     pop    ds            ; pop environment segment
  2922.     pop    si            ; pop environment offset
  2923.     pop    cx            ; pop environment length
  2924.     mov    di,swapbeg        ;e environment destination
  2925.                     ;d Zieladresse Umgebungsblock
  2926. ;
  2927. ;e    Push return address on local stack
  2928. ;d    Rückkehradresse auf lokalen Stack bringen
  2929. ;
  2930.     push    cs            ;e push return segment
  2931.                     ;d Rückkehr-Segment pushen
  2932.     mov    ax,offset exec_cont
  2933.     push    ax            ;e push return offset
  2934.                     ;d Rückkehr-Offset pushen
  2935.     mov    es:spx,sp        ;e save stack pointer
  2936.                     ;d Stack-Zeiger sichern
  2937. ;
  2938. ;e    Goto low core code
  2939. ;d    In den residenten Teil springen
  2940. ;
  2941.     push    es            ;e push entry segment
  2942.                     ;d Einsprungssegment pushen
  2943.         mov    ax,codebeg + doexec_entry
  2944.         push    ax            ;e push entry offset
  2945.                     ;d Einsprungsoffset pushen
  2946. ;e    ret    far            ; can't use RET here because
  2947. ;d    ret    far            ; RET kann hier wegen der .model-
  2948.     db    0cbh            ;e of .model
  2949.                     ;d Direktive nicht verwendet werden
  2950. ;
  2951. ;----------------------------------------------------------------
  2952. ;>e
  2953. ;    Low core code will return to this location, with DS set to
  2954. ;    the PSP segment.
  2955. ;<
  2956. ;>d
  2957. ;    Der residente Teil kehrt hierher zurück, mit DS = PSP-Segment.
  2958. ;<
  2959. exec_cont:
  2960.     push    ds
  2961.     pop    es
  2962.     cli
  2963.     mov    ss,ds:save_ss        ;e reload stack
  2964.                     ;d Stack zurückladen
  2965.     mov    sp,ds:save_sp
  2966.     sti
  2967. ;
  2968. ;e    restore handle table and pointer
  2969. ;d    Wiederherstellen Handle-Tabelle und Pointer
  2970. ;
  2971.     IF    NO_INHERIT
  2972.     mov    si,lhandlesave
  2973.     mov    di,psp_handletab
  2974.     mov    cx,10
  2975.     rep movsw
  2976.     mov    di,psp_handlenum
  2977.     movsw
  2978.     movsw
  2979.     movsw
  2980.     ENDIF
  2981. ;
  2982. ;e    restore INT0 (division by zero) vector
  2983. ;d    INT0 (division by zero) Vektor wiederherstellen
  2984. ;
  2985.     xor    cx,cx
  2986.     mov    ds,cx
  2987.     mov    cx,es:div0_off
  2988.     mov    word ptr ds:0,cx
  2989.     mov    cx,es:div0_seg
  2990.     mov    word ptr ds:2,cx
  2991. ;
  2992.     mov    ds,datseg
  2993. ;
  2994.     IFDEF    PASCAL
  2995.     IF    PAS_FREE
  2996.     push    es
  2997.     call    @restpas
  2998.     pop    es
  2999.     ENDIF
  3000.     ENDIF
  3001. ;
  3002.     mov    ax,es:eretcode
  3003.     mov    bx,es:retflags
  3004. ;
  3005. ;e    Restore overwritten part of program
  3006. ;d    Den überschriebenen Teil des Programms wiederherstellen
  3007. ;
  3008.     mov    si,offset save_dat
  3009.     mov    di,5ch
  3010.     mov    cx,savespace
  3011.     rep movsb
  3012. ;
  3013.     test    bx,1            ;e carry set?
  3014.                     ;d Carry-Flag gesetzt?
  3015.     jnz    exec_fault        ;e return EXEC error code if fault
  3016.                     ;d EXEC Fehler-code liefern wenn ja
  3017.     mov    ah,4dh            ;e else get program return code
  3018.                     ;d Sonst Programm-Rückgabewert holen
  3019.     int    21h
  3020.     ret
  3021. ;
  3022. exec_fault:
  3023.     mov    ah,3            ;e return error as 03xx
  3024.                     ;d EXEC-Fehler als 03xx liefern
  3025.     ret
  3026. ;    
  3027. do_spawn    ENDP
  3028. ;
  3029. ;----------------------------------------------------------------------------
  3030. ;----------------------------------------------------------------------------
  3031. ;
  3032. emm_name    db    'EMMXXXX0'
  3033. ;>e
  3034. ;    prep_swap - prepare for swapping.
  3035. ;
  3036. ;    This routine checks all parameters necessary for swapping,
  3037. ;    and attempts to set up the swap-out area in EMS/XMS, or on file.
  3038. ;    In detail:
  3039. ;
  3040. ;         1) Check whether the do_spawn routine is located
  3041. ;        too low in memory, so it would get overwritten.
  3042. ;        If this is true, return an error code (-2).
  3043. ;
  3044. ;         2) Walk the memory control block chain, adding up the
  3045. ;        paragraphs in all blocks assigned to this process.
  3046. ;
  3047. ;         3) Check EMS (if the method parameter allows EMS):
  3048. ;        - is an EMS driver installed?
  3049. ;        - are sufficient EMS pages available?
  3050. ;        if all goes well, the EMS pages are allocated, and the
  3051. ;        routine returns success (1).
  3052. ;
  3053. ;         4) Check XMS (if the method parameter allows XMS):
  3054. ;        - is an XMS driver installed?
  3055. ;        - is a sufficient XMS block available?
  3056. ;        if all goes well, the XMS block is allocated, and the
  3057. ;        routine returns success (2).
  3058. ;
  3059. ;         5) Check file swap (if the method parameter allows it):
  3060. ;        - try to create the file
  3061. ;        - pre-allocate the file space needed by seeking to the end
  3062. ;          and writing a byte.
  3063. ;        If the file can be written, the routine returns success (4).
  3064. ;
  3065. ;         6) Return an error code (-1).
  3066. ;<
  3067. ;>d
  3068. ;    prep_swap - Auslagerung vorbereiten.
  3069. ;
  3070. ;    Diese Routine prüft die zur Auslagerung nötigen Parameter,
  3071. ;    und versucht den Auslagerungsbereich in EMS, XMS, oder auf Datei,
  3072. ;    vorzubereiten.
  3073. ;    Im einzelnen:
  3074. ;
  3075. ;         1) Prüfen ob die do_spawn-Routine so niedrig liegt daß
  3076. ;        sie durch die Auslagerung überschrieben würde.
  3077. ;        Ist dies der Fall, Fehler (-2) liefern.
  3078. ;
  3079. ;         2) Die MCB-Kette durchlaufen, dabei die Länge in Paragraphen
  3080. ;        aller Blöcke addieren die zu diesem Prozeß gehören.
  3081. ;
  3082. ;         3) EMS prüfen (wenn der method Parameter EMS erlaubt):
  3083. ;        - ist ein EMS Treiber installiert?
  3084. ;        - sind genügend EMS-Seiten verfügbar?
  3085. ;        Wenn dies erfüllt ist, werden die EMS-Seiten alloziert,
  3086. ;        und die Routine liefert einen Erfolgscode (1).
  3087. ;
  3088. ;         4) XMS prüfen (wenn der method Parameter XMS erlaubt):
  3089. ;        - ist ein XMS Treiber installiert?
  3090. ;        - ist ein ausreichend großer XMS-Bereich verfügbar?
  3091. ;        Wenn dies erfüllt ist, wird der XMS-Bereich alloziert,
  3092. ;        und die Routine liefert einen Erfolgscode (2).
  3093. ;
  3094. ;         5) Dateiauslagerung prüfen (wenn der method Parameter es erlaubt):
  3095. ;        - die Datei erzeugen,
  3096. ;        - den benötigten Platz auf Datei prä-allozieren indem
  3097. ;          an das Ende positioniert und ein Byte geschrieben wird.
  3098. ;        Konnte die Datei geschrieben werden, liefert die Routine
  3099. ;        einen Erfolgscode (4).
  3100. ;
  3101. ;         6) Fehlercode liefern (-1).
  3102. ;<
  3103.     IFDEF    PASCAL
  3104.     IFDEF    FARCALL
  3105. prep_swap    PROC    far pmethod: word, swapfname: dword
  3106.     ELSE
  3107. prep_swap    PROC    near pmethod: word, swapfname: dword
  3108.     ENDIF
  3109.     ELSE
  3110. prep_swap    PROC    uses si di,pmethod:word,swapfname:ptr byte
  3111.     ENDIF
  3112.     LOCAL    totparas: word
  3113. ;
  3114.     IFDEF    TC_HUGE
  3115.     mov    ax,SEG my_data
  3116.     mov    ds,ax
  3117.     ENDIF
  3118. ;
  3119.     IFDEF    PASCAL
  3120.     cld
  3121.     mov    ax,prefixseg
  3122.     ELSE
  3123.     IFDEF    TC_HUGE
  3124.     mov    ax,SEG _psp
  3125.     mov    es,ax
  3126.     mov    ax,es:_psp
  3127.     ELSE
  3128.     mov    ax,_psp
  3129.     ENDIF
  3130.     ENDIF
  3131. ;
  3132.     dec    ax
  3133.     mov    swap_prep.psp_mcb,ax
  3134.     mov    swap_prep.first_mcb,ax    ;e init first MCB to PSP
  3135.                     ;d ersten MCB auf PSP initialisieren
  3136. ;
  3137. ;e    Make a copy of the environment pointer in the PSP
  3138. ;d    Eine Kopie vom Umgebungsvariablenblock-Pointer des PSP sichern
  3139. ;
  3140.     inc    ax
  3141.     mov    es,ax
  3142.     mov    bx,es:psp_envptr
  3143.     dec    bx
  3144.     mov    swap_prep.env_mcb,bx
  3145.     mov    swap_prep.noswap_mcb,0
  3146.     test    pmethod,DONT_SWAP_ENV
  3147.     jz    can_swap_env
  3148.     mov    swap_prep.noswap_mcb,bx
  3149. ;
  3150. can_swap_env:
  3151.     IF    NOT NO_INHERIT
  3152.     push    ax
  3153.     mov    swap_prep.noswap_mcb2,0
  3154.     mov    ax,3000h
  3155.     int    21h
  3156.     cmp    al,3
  3157.     jb    no_exthandle
  3158.     ja    check_exthandle
  3159.     cmp    ah,33
  3160.     jb    no_exthandle
  3161. ;
  3162. check_exthandle:
  3163.     mov    ax,es:psp_handleptrs
  3164.     mov    bx,es
  3165.     cmp    ax,bx
  3166.     je    no_exthandle
  3167.     dec    ax
  3168.     mov    swap_prep.noswap_mcb2,ax
  3169. ;
  3170. no_exthandle:
  3171.     pop    ax
  3172.     ENDIF
  3173. ;
  3174. ;e    Check if spawn is too low in memory
  3175. ;d    Prüfen ob dieses Modul zu weit unten im Speicher liegt
  3176. ;
  3177.     mov    bx,cs
  3178.     mov    dx,offset lowcode_begin
  3179.     mov    cl,4
  3180.     shr    dx,cl
  3181.     add    bx,dx            ;e normalized start of this code
  3182.                     ;d Normalisierter Beginn des Codes
  3183.     mov    dx,keep_paras        ;e the end of the modified area
  3184.                     ;d Ende des modifizierten Bereichs
  3185.     add    dx,ax            ;e plus PSP = end paragraph
  3186.                     ;d plus PSP = letzer Paragraph
  3187.     cmp    bx,dx
  3188.     ja    prepswap_ok    ;e ok if start of code > end of low mem
  3189.                 ;d OK wenn Code-Beginn > Ende residenter Teil
  3190.     mov    ax,-2
  3191.     mov    swap_prep.swapmethod,al
  3192.     ret
  3193. ;>e
  3194. ;    Walk the chain of memory blocks, adding up the paragraphs
  3195. ;    in all blocks belonging to this process.
  3196. ;    We try to find the first MCB by getting DOS's "list of lists",
  3197. ;    and fetching the word at offset -2 of the returned address.
  3198. ;    If this fails, we use our PSP as the starting point.
  3199. ;<
  3200. ;>d
  3201. ;    Die Speicherblöcke durchgehen und die Größe aller zu diesem
  3202. ;    Prozeß gehörenden Blöcke zusammenzählen.
  3203. ;    Der Anfang der MCB-Liste wird aus der DOS "list of lists"
  3204. ;    abgeleitet. Das Wort an Offset -2 der gelieferten Adresse
  3205. ;    enthält die erste MCB-Adresse. Falls dies fehlschlägt, wird
  3206. ;    der PSP als Ausgangspunkt benutzt.
  3207. ;<
  3208. prepswap_ok:
  3209.     IFDEF    PASCAL
  3210.     IF    PAS_FREE
  3211.     call    @freepas
  3212.     ENDIF
  3213.     ENDIF
  3214.     xor    bx,bx
  3215.     mov    es,bx
  3216.     mov    ah,52h            ; get list of lists
  3217.     int    21h
  3218.     mov    ax,es
  3219.     or    ax,bx
  3220.     jz    prep_no_first
  3221.     mov    es,es:[bx-2]        ; first MCB
  3222.     cmp    es:id,4dh        ; normal ID?
  3223.     jne    prep_no_first
  3224.     mov    swap_prep.first_mcb,es
  3225. ;
  3226. prep_no_first:
  3227.     mov    es,swap_prep.psp_mcb    ;e ES points to base MCB
  3228.                     ;d ES zeigt auf Basis-Block
  3229.     mov    cx,es            ;e save this value
  3230.                     ;d diesen Wert sichern
  3231.     mov    bx,es:owner        ;e the current process
  3232.                     ;d Der aktuelle Prozeß
  3233.     mov    dx,es:paras        ;e memory size in the base block
  3234.                     ;d Speichergröße des Basisblocks
  3235.     sub    dx,keep_paras        ;e minus resident paragraphs
  3236.                     ;d Abzüglich residente Paragraphen
  3237.     mov    si,0            ;e number of MCBs except base
  3238.                     ;d Zähler für MCBs außer Basis
  3239.     mov    di,swap_prep.noswap_mcb
  3240.     mov    ax,swap_prep.first_mcb
  3241.     mov    swap_prep.first_mcb,0
  3242. ;
  3243. prep_mcb_walk:
  3244.     mov    es,ax
  3245.     cmp    ax,cx            ;e base block?
  3246.                     ;d Basisblock?
  3247.     je    prep_walk_next        ;e then don't count again
  3248.                     ;d dann nicht nochmal zählen
  3249.     cmp    ax,di            ;e Non-swap MCB?
  3250.     je    prep_walk_next        ;e then don't count
  3251.                     ;d dann nicht zählen
  3252.     IF    NOT NO_INHERIT
  3253.     cmp    ax,swap_prep.noswap_mcb2
  3254.     je    prep_walk_next
  3255.     ENDIF
  3256. ;
  3257.     cmp    bx,es:owner        ;e our process?
  3258.                     ;d aktueller Prozeß?
  3259.     jne    prep_walk_next        ;e next if not
  3260.                     ;d nächsten wenn nein
  3261.     inc    si
  3262.     mov    ax,es:paras        ;e else get number of paragraphs
  3263.                     ;d sonst Größe in Paragraphen laden
  3264.     add    ax,2            ; + 1 for descriptor + 1 for MCB
  3265.     add    dx,ax            ;e total number of paras
  3266.                     ;d Gesamtzahl Paragraphen
  3267.     cmp    swap_prep.first_mcb,0
  3268.     jne    prep_walk_next
  3269.     mov    swap_prep.first_mcb,es
  3270. ;
  3271. prep_walk_next:
  3272.     cmp    es:id,4dh        ;e normal block?
  3273.                     ;d normaler Block?
  3274.     jne    prep_mcb_ready        ;e ready if end of chain
  3275.                     ;d Fertig wenn ende der Kette
  3276.     mov    ax,es
  3277.     add    ax,es:paras        ; start + length
  3278.     inc    ax            ; next MCB
  3279.     jmp    prep_mcb_walk
  3280. ;
  3281. prep_mcb_ready:
  3282.     mov    totparas,dx
  3283.     mov    swap_prep.total_mcbs,si
  3284. ;
  3285.     IFDEF    PASCAL
  3286.     IF    PAS_FREE
  3287.     call    @restpas
  3288.     ENDIF
  3289.     ENDIF
  3290. ;
  3291.     test    pmethod,XMS_FIRST
  3292.     jnz    check_xms
  3293. ;
  3294. ;e    Check for EMS swap
  3295. ;d    EMS-auslagerung prüfen
  3296. ;
  3297. check_ems:
  3298.     test    pmethod,USE_EMS
  3299.     jz    prep_no_ems
  3300. ;
  3301.     push    ds
  3302.     mov    al,EMM_INT
  3303.     mov    ah,35h
  3304.     int    21h            ;e get EMM int vector
  3305.                     ;d EMM-Interrupt Vektor laden
  3306.     mov    ax,cs
  3307.     mov    ds,ax
  3308.     mov    si,offset emm_name
  3309.     mov    di,10
  3310.     mov    cx,8
  3311.     repz cmpsb            ;e EMM name present?
  3312.                     ;d ist der EMM-Name vorhanden?
  3313.     pop    ds
  3314.     jnz    prep_no_ems
  3315. ;
  3316.     mov    ah,40h            ;e get EMS status
  3317.                     ;d EMS-Status abfragen
  3318.     int    EMM_INT
  3319.     or    ah,ah            ; EMS ok?
  3320.     jnz    prep_no_ems
  3321. ;
  3322.     mov    ah,46h            ;e get EMS version
  3323.                     ;d EMS-Version abfragen
  3324.     int    EMM_INT
  3325.     or    ah,ah            ; AH must be 0
  3326.     jnz    prep_no_ems
  3327. ;
  3328.     cmp    al,30h            ; >= version 3.0?
  3329.     jb    prep_no_ems
  3330. ;
  3331.     mov    ah,41h            ;e Get page frame address
  3332.                     ;d EMS-Frame-Adresse holen
  3333.     int    EMM_INT
  3334.     or    ah,ah
  3335.     jnz    prep_no_ems
  3336. ;
  3337. ;e    EMS present, try to allocate pages
  3338. ;d    EMS vorhanden, versuche Seiten zu allozieren
  3339. ;
  3340.     mov    swap_prep.ems_pageframe,bx
  3341.     mov    bx,totparas
  3342.     add    bx,ems_paramask
  3343.     mov    cl,ems_shift
  3344.     shr    bx,cl
  3345.     mov    ah,43h            ; allocate handle and pages
  3346.     int    EMM_INT
  3347.     or    ah,ah            ;e success?
  3348.                     ;d erfolgreich?
  3349.     jnz    prep_no_ems
  3350. ;
  3351. ;e    EMS pages allocated, swap to EMS
  3352. ;d    EMS-Seiten alloziert, auslagern auf EMS
  3353. ;
  3354.     mov    swap_prep.handle,dx
  3355.     mov    ax,USE_EMS
  3356.     mov    swap_prep.swapmethod,al
  3357.     ret
  3358. ;
  3359. ;e    No EMS allowed, or EMS not present/full. Try XMS.
  3360. ;d    EMS nicht erlaubt, oder EMS nicht vorhanden/voll. XMS versuchen.
  3361. ;
  3362. prep_no_ems:
  3363.     test    pmethod,XMS_FIRST
  3364.     jnz    check_file        ;e don't try again
  3365.                     ;d nicht nochmal versuchen
  3366. ;
  3367. check_xms:
  3368.     test    pmethod,USE_XMS
  3369.     jz    prep_no_xms
  3370. ;
  3371.     mov    ax,4300h        ;e check if XMM driver present
  3372.                     ;d prüfen ob XMM-Treiber vorhanden
  3373.     int    2fh
  3374.     cmp    al,80h            ;e is XMM installed?
  3375.                     ;d ist XMM installiert?
  3376.     jne    prep_no_xms
  3377.     mov    ax,4310h        ;e get XMM entrypoint
  3378.                     ;d XMM-Einsprungadresse holen
  3379.     int    2fh
  3380.     mov    word ptr swap_prep.xmm,bx    ;e save entry address
  3381.                     ;d Einsprungadresse sichern
  3382.     mov    word ptr swap_prep.xmm+2,es
  3383. ;
  3384.     mov    dx,totparas
  3385.     add    dx,xms_paramask        ;e round to nearest multiple of 1k
  3386.                     ;d Auf volle 1k aufrunden
  3387.     mov    cl,xms_shift
  3388.     shr    dx,cl            ;e convert to k
  3389.                     ;d konvertiern in k
  3390.     mov    ah,9            ;e allocate extended memory block
  3391.                     ;d Extended memory block allozieren
  3392.     call    swap_prep.xmm
  3393.     or    ax,ax
  3394.     jz    prep_no_xms
  3395. ;
  3396. ;e    XMS block allocated, swap to XMS
  3397. ;d    XMS-Block alloziert, Auslagern auf XMS.
  3398. ;
  3399.     mov    swap_prep.handle,dx
  3400.     mov    ax,USE_XMS
  3401.     mov    swap_prep.swapmethod,al
  3402.     ret
  3403. ;
  3404. ;e    No XMS allowed, or XMS not present/full. Try File swap.
  3405. ;d    XMS nicht erlaubt, oder XMS nicht vorhanden/voll. Datei versuchen.
  3406. ;
  3407. prep_no_xms:
  3408.     test    pmethod,XMS_FIRST
  3409.     jz    check_file
  3410.     jmp    check_ems
  3411. ;
  3412. check_file:
  3413.     test    pmethod,USE_FILE
  3414.     jnz    prep_do_file
  3415.     jmp    prep_no_file
  3416. ;
  3417. prep_do_file:
  3418.     push    ds
  3419.     IF    ptrsize
  3420.     lds    dx,swapfname
  3421.     ELSE
  3422.     mov    dx,swapfname
  3423.     ENDIF
  3424.     IFDEF    PASCAL
  3425.     inc    dx            ;e skip length byte
  3426.                     ;d Längenbyte überspringen
  3427.     ENDIF
  3428.     mov    cx,2            ; hidden attribute
  3429.     test    pmethod,HIDE_FILE
  3430.     jnz    prep_hide
  3431.     xor    cx,cx            ; normal attribute
  3432. ;
  3433. prep_hide:
  3434.     mov    ah,3ch            ; create file
  3435.     test    pmethod,CREAT_TEMP
  3436.     jz    prep_no_temp
  3437.     mov    ah,5ah
  3438. ;
  3439. prep_no_temp:
  3440.     int    21h            ; create/create temp
  3441.     jnc    prep_got_file
  3442.     jmp    prep_no_file
  3443. ;
  3444. prep_got_file:
  3445.     mov    bx,ax            ; handle
  3446. ;
  3447. ;e    save the file name
  3448. ;d    Dateinamen sichern
  3449. ;
  3450.     pop    es
  3451.     push    es
  3452.     mov    di,offset swap_prep.swapfilename
  3453.     mov    cx,81
  3454.     mov    si,dx
  3455.     rep movsb
  3456. ;
  3457.     pop    ds
  3458.     mov    swap_prep.handle,bx
  3459. ;
  3460. ;e    preallocate the file
  3461. ;d    Datei-Speicherplatz prä-allozieren
  3462. ;
  3463.     test    pmethod,NO_PREALLOC
  3464.     jnz    prep_noprealloc
  3465.     test    pmethod,CHECK_NET
  3466.     jz    prep_nonetcheck
  3467. ;
  3468. ;e    check whether file is on a network drive, and don't preallocate
  3469. ;e    if so. preallocation can slow down swapping significantly when
  3470. ;e    running on certain networks (Novell)
  3471. ;d    Prüfen ob Datei auf einem Netwerk-Laufwerk liegt, und nicht
  3472. ;d    präallozieren wenn ja. Ein Präallozieren kann den Swap-Vorgang
  3473. ;d    erheblich verlangsamen wenn es auf Novell-Drives ausgeführt wird.
  3474. ;
  3475.     mov    ax,440ah    ; check if handle is remote
  3476.     int    21h
  3477.     jc    prep_nonetcheck    ;e assume not remote if function fails
  3478.                 ;d kein Netz wenn Funktion Fehler liefert
  3479.     test    dh,80h        ;e DX bit 15 set ?
  3480.                 ;d Ist Bit 15 von DX gesetzt?
  3481.     jnz    prep_noprealloc    ;e remote if yes
  3482.                 ;d Netzwerk-Datei wenn ja
  3483. ;
  3484. prep_nonetcheck:
  3485.     mov    dx,totparas
  3486.     mov    cl,4
  3487.     rol    dx,cl
  3488.     mov    cx,dx
  3489.     and    dx,0fff0h
  3490.     and    cx,0000fh
  3491.     sub    dx,1
  3492.     sbb    cx,0
  3493.     mov    si,dx            ; save
  3494.     mov    ax,4200h        ; move file pointer, absolute
  3495.     int    21h
  3496.     jc    prep_file_err
  3497.     cmp    dx,cx
  3498.     jne    prep_file_err
  3499.     cmp    ax,si
  3500.     jne    prep_file_err
  3501.     mov    cx,1            ;e write 1 byte
  3502.                     ;d 1 Byte schreiben
  3503.     mov    ah,40h
  3504.     int    21h
  3505.     jc    prep_file_err
  3506.     cmp    ax,cx
  3507.     jne    prep_file_err
  3508. ;
  3509.     mov    ax,4200h        ; move file pointer, absolute
  3510.     xor    dx,dx
  3511.     xor    cx,cx            ;e rewind to beginning
  3512.                     ;d Auf Anfang zurückpositionieren
  3513.     int    21h
  3514.     jc    prep_file_err
  3515. ;
  3516. prep_noprealloc:
  3517.     mov    ax,USE_FILE
  3518.     mov    swap_prep.swapmethod,al
  3519.     ret
  3520. ;
  3521. prep_file_err:
  3522.     mov    ah,3eh            ; close file
  3523.     int    21h
  3524.     mov    dx,offset swap_prep.swapfilename
  3525.     mov    ah,41h            ; delete file
  3526.     int    21h
  3527. ;
  3528. prep_no_file:
  3529.     mov    ax,-1
  3530.     mov    swap_prep.swapmethod,al
  3531.     ret
  3532. ;
  3533. prep_swap    endp
  3534. ;
  3535.     end
  3536.  
  3537.